Commit dc1ce798 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Add support to the activex, mozilla, firefox, safari plugin for changing audio...

Add support to the activex, mozilla, firefox, safari plugin for changing audio track and audio output channel (reverse, stereo, left, right, dolby).
parent 53a76832
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006 the VideoLAN team
* *
* Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net> * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
* Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -198,6 +199,16 @@ library AXVLC ...@@ -198,6 +199,16 @@ library AXVLC
[helpstring("Mute/unmute audio playback.")] [helpstring("Mute/unmute audio playback.")]
HRESULT toggleMute(); HRESULT toggleMute();
[propget, helpstring("Returns/sets audio track used/to use.")]
HRESULT track([out, retval] long* track);
[propput, helpstring("Returns/sets audio track used/to use.")]
HRESULT track([in] long track);
[propget, helpstring("Returns audio channel: reverse, stereo, left, right, dolby.")]
HRESULT channel([out, retval] BSTR* channel);
[propput, helpstring("Sets audio channel to: reverse, stereo, left, right, dolby.")]
HRESULT channel([in] BSTR channel);
}; };
[ [
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006 the VideoLAN team
* *
* Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net> * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
* Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -198,6 +199,119 @@ STDMETHODIMP VLCAudio::put_volume(long volume) ...@@ -198,6 +199,119 @@ STDMETHODIMP VLCAudio::put_volume(long volume)
return hr; return hr;
}; };
STDMETHODIMP VLCAudio::get_track(long* track)
{
if( NULL == track )
return E_POINTER;
libvlc_instance_t* p_libvlc;
HRESULT hr = _p_instance->getVLC(&p_libvlc);
if( SUCCEEDED(hr) )
{
libvlc_exception_t ex;
libvlc_exception_init(&ex);
*track = libvlc_audio_get_track(p_libvlc, &ex);
if( libvlc_exception_raised(&ex) )
{
_p_instance->setErrorInfo(IID_IVLCAudio, libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return E_FAIL;
}
return NOERROR;
}
return hr;
};
STDMETHODIMP VLCAudio::put_track(long track)
{
libvlc_instance_t* p_libvlc;
HRESULT hr = _p_instance->getVLC(&p_libvlc);
if( SUCCEEDED(hr) )
{
libvlc_exception_t ex;
libvlc_exception_init(&ex);
libvlc_audio_set_track(p_libvlc, track, &ex);
if( libvlc_exception_raised(&ex) )
{
_p_instance->setErrorInfo(IID_IVLCAudio, libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return E_FAIL;
}
return NOERROR;
}
return hr;
};
STDMETHODIMP VLCAudio::get_channel(BSTR *channel)
{
if( NULL == channel )
return E_POINTER;
libvlc_instance_t* p_libvlc;
HRESULT hr = _p_instance->getVLC(&p_libvlc);
if( SUCCEEDED(hr) )
{
char *psz_channel = NULL;
libvlc_exception_t ex;
libvlc_exception_init(&ex);
psz_channel = libvlc_audio_get_channel(p_libvlc, &ex);
if( ! libvlc_exception_raised(&ex) )
{
if( NULL == psz_channel )
return E_OUTOFMEMORY;
*channel = SysAllocStringByteLen(psz_channel, strlen(psz_channel));
free( psz_channel );
psz_channel = NULL;
return NOERROR;
}
if( psz_channel ) free( psz_channel );
_p_instance->setErrorInfo(IID_IVLCAudio,
libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return E_FAIL;
}
return hr;
};
STDMETHODIMP VLCAudio::put_channel(BSTR channel)
{
if( NULL == channel )
return E_POINTER;
if( 0 == SysStringLen(channel) )
return E_INVALIDARG;
libvlc_instance_t* p_libvlc;
HRESULT hr = _p_instance->getVLC(&p_libvlc);
if( SUCCEEDED(hr) )
{
char *psz_channel = NULL;
libvlc_exception_t ex;
libvlc_exception_init(&ex);
psz_channel = CStrFromBSTR(CP_UTF8, channel);
if( NULL == psz_channel )
return E_OUTOFMEMORY;
libvlc_audio_set_channel(p_libvlc, psz_channel, &ex);
CoTaskMemFree(psz_channel);
if( libvlc_exception_raised(&ex) )
{
_p_instance->setErrorInfo(IID_IVLCAudio,
libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return E_FAIL;
}
return NOERROR;
}
return hr;
};
STDMETHODIMP VLCAudio::toggleMute() STDMETHODIMP VLCAudio::toggleMute()
{ {
libvlc_instance_t* p_libvlc; libvlc_instance_t* p_libvlc;
...@@ -2261,7 +2375,7 @@ STDMETHODIMP VLCControl2::get_Visible(VARIANT_BOOL *isVisible) ...@@ -2261,7 +2375,7 @@ STDMETHODIMP VLCControl2::get_Visible(VARIANT_BOOL *isVisible)
return NOERROR; return NOERROR;
}; };
STDMETHODIMP VLCControl2::put_Visible(VARIANT_BOOL isVisible) STDMETHODIMP VLCControl2::put_Visible(VARIANT_BOOL isVisible)
{ {
_p_instance->setVisible(isVisible != VARIANT_FALSE); _p_instance->setVisible(isVisible != VARIANT_FALSE);
...@@ -2277,7 +2391,7 @@ STDMETHODIMP VLCControl2::get_Volume(long *volume) ...@@ -2277,7 +2391,7 @@ STDMETHODIMP VLCControl2::get_Volume(long *volume)
*volume = _p_instance->getVolume(); *volume = _p_instance->getVolume();
return NOERROR; return NOERROR;
}; };
STDMETHODIMP VLCControl2::put_Volume(long volume) STDMETHODIMP VLCControl2::put_Volume(long volume)
{ {
_p_instance->setVolume(volume); _p_instance->setVolume(volume);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006 the VideoLAN team
* *
* Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net> * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
* Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -65,8 +66,12 @@ public: ...@@ -65,8 +66,12 @@ public:
STDMETHODIMP put_mute(VARIANT_BOOL); STDMETHODIMP put_mute(VARIANT_BOOL);
STDMETHODIMP get_volume(long*); STDMETHODIMP get_volume(long*);
STDMETHODIMP put_volume(long); STDMETHODIMP put_volume(long);
STDMETHODIMP get_track(long*);
STDMETHODIMP put_track(long);
STDMETHODIMP get_channel(BSTR*);
STDMETHODIMP put_channel(BSTR);
STDMETHODIMP toggleMute(); STDMETHODIMP toggleMute();
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -75,7 +80,7 @@ private: ...@@ -75,7 +80,7 @@ private:
ITypeInfo* _p_typeinfo; ITypeInfo* _p_typeinfo;
}; };
class VLCInput : public IVLCInput class VLCInput : public IVLCInput
{ {
public: public:
...@@ -130,7 +135,7 @@ private: ...@@ -130,7 +135,7 @@ private:
ITypeInfo* _p_typeinfo; ITypeInfo* _p_typeinfo;
}; };
class VLCMessage: public IVLCMessage class VLCMessage: public IVLCMessage
{ {
public: public:
...@@ -184,7 +189,7 @@ public: ...@@ -184,7 +189,7 @@ public:
STDMETHODIMP get_name(BSTR *); STDMETHODIMP get_name(BSTR *);
STDMETHODIMP get_header(BSTR *); STDMETHODIMP get_header(BSTR *);
STDMETHODIMP get_message(BSTR *); STDMETHODIMP get_message(BSTR *);
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -195,7 +200,7 @@ private: ...@@ -195,7 +200,7 @@ private:
struct libvlc_log_message_t _msg; struct libvlc_log_message_t _msg;
}; };
class VLCLog; class VLCLog;
class VLCMessageIterator : public IVLCMessageIterator class VLCMessageIterator : public IVLCMessageIterator
...@@ -255,7 +260,7 @@ private: ...@@ -255,7 +260,7 @@ private:
VLCLog* _p_vlclog; VLCLog* _p_vlclog;
libvlc_log_iterator_t* _p_iter; libvlc_log_iterator_t* _p_iter;
}; };
class VLCMessages : public IVLCMessages class VLCMessages : public IVLCMessages
{ {
public: public:
...@@ -297,7 +302,7 @@ public: ...@@ -297,7 +302,7 @@ public:
STDMETHODIMP clear(); STDMETHODIMP clear();
STDMETHODIMP get_count(long*); STDMETHODIMP get_count(long*);
STDMETHODIMP iterator(IVLCMessageIterator**); STDMETHODIMP iterator(IVLCMessageIterator**);
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -355,7 +360,7 @@ public: ...@@ -355,7 +360,7 @@ public:
STDMETHODIMP get_messages(IVLCMessages**); STDMETHODIMP get_messages(IVLCMessages**);
STDMETHODIMP get_verbosity(long *); STDMETHODIMP get_verbosity(long *);
STDMETHODIMP put_verbosity(long); STDMETHODIMP put_verbosity(long);
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -367,7 +372,7 @@ private: ...@@ -367,7 +372,7 @@ private:
VLCMessages* _p_vlcmessages; VLCMessages* _p_vlcmessages;
}; };
class VLCPlaylistItems : public IVLCPlaylistItems class VLCPlaylistItems : public IVLCPlaylistItems
{ {
public: public:
...@@ -405,7 +410,7 @@ public: ...@@ -405,7 +410,7 @@ public:
STDMETHODIMP get_count(long*); STDMETHODIMP get_count(long*);
STDMETHODIMP clear(); STDMETHODIMP clear();
STDMETHODIMP remove(long); STDMETHODIMP remove(long);
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -414,7 +419,7 @@ private: ...@@ -414,7 +419,7 @@ private:
ITypeInfo* _p_typeinfo; ITypeInfo* _p_typeinfo;
}; };
class VLCPlaylist : public IVLCPlaylist class VLCPlaylist : public IVLCPlaylist
{ {
public: public:
...@@ -466,7 +471,7 @@ public: ...@@ -466,7 +471,7 @@ public:
STDMETHODIMP clear(); STDMETHODIMP clear();
STDMETHODIMP removeItem(long); STDMETHODIMP removeItem(long);
STDMETHODIMP get_items(IVLCPlaylistItems**); STDMETHODIMP get_items(IVLCPlaylistItems**);
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -476,7 +481,7 @@ private: ...@@ -476,7 +481,7 @@ private:
VLCPlaylistItems* _p_vlcplaylistitems; VLCPlaylistItems* _p_vlcplaylistitems;
}; };
class VLCVideo : public IVLCVideo class VLCVideo : public IVLCVideo
{ {
public: public:
...@@ -518,7 +523,7 @@ public: ...@@ -518,7 +523,7 @@ public:
STDMETHODIMP get_aspectRatio(BSTR*); STDMETHODIMP get_aspectRatio(BSTR*);
STDMETHODIMP put_aspectRatio(BSTR); STDMETHODIMP put_aspectRatio(BSTR);
STDMETHODIMP toggleFullscreen(); STDMETHODIMP toggleFullscreen();
protected: protected:
HRESULT loadTypeInfo(); HRESULT loadTypeInfo();
...@@ -527,10 +532,9 @@ private: ...@@ -527,10 +532,9 @@ private:
ITypeInfo* _p_typeinfo; ITypeInfo* _p_typeinfo;
}; };
class VLCControl2 : public IVLCControl2 class VLCControl2 : public IVLCControl2
{ {
public: public:
VLCControl2(VLCPlugin *p_instance); VLCControl2(VLCPlugin *p_instance);
...@@ -597,6 +601,5 @@ private: ...@@ -597,6 +601,5 @@ private:
VLCPlaylist* _p_vlcplaylist; VLCPlaylist* _p_vlcplaylist;
VLCVideo* _p_vlcvideo; VLCVideo* _p_vlcvideo;
}; };
#endif
#endif
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* $Id: vlc.h 13701 2005-12-12 17:58:56Z zorglub $ * $Id: vlc.h 13701 2005-12-12 17:58:56Z zorglub $
* *
* Authors: Clément Stenac <zorglub@videolan.org> * Authors: Clément Stenac <zorglub@videolan.org>
* Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -486,7 +487,41 @@ int libvlc_audio_get_volume( libvlc_instance_t *, libvlc_exception_t * ); ...@@ -486,7 +487,41 @@ int libvlc_audio_get_volume( libvlc_instance_t *, libvlc_exception_t * );
* \param p_exception an initialized exception * \param p_exception an initialized exception
* \return void * \return void
*/ */
void libvlc_audio_set_volume( libvlc_instance_t *, int , libvlc_exception_t *); void libvlc_audio_set_volume( libvlc_instance_t *, int, libvlc_exception_t *);
/**
* Get current audio track
* \param p_instance libvlc instance
* \param p_exception an initialized exception
* \return the audio track (int)
*/
int libvlc_audio_get_track( libvlc_instance_t *, libvlc_exception_t * );
/**
* Set current audio track
* \param p_instance libvlc instance
* \param i_track the track (int)
* \param p_exception an initialized exception
* \return void
*/
void libvlc_audio_set_track( libvlc_instance_t *, int, libvlc_exception_t * );
/**
* Get current audio channel
* \param p_instance libvlc instance
* \param p_exception an initialized exception
* \return the audio channel (char *)
*/
char *libvlc_audio_get_channel( libvlc_instance_t *, libvlc_exception_t * );
/**
* Set current audio track
* \param p_instance libvlc instance
* \param psz_channel the audio channel (char *)
* \param p_exception an initialized exception
* \return void
*/
void libvlc_audio_set_channel( libvlc_instance_t *, char *, libvlc_exception_t * );
/** @} */ /** @} */
......
...@@ -177,6 +177,8 @@ const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] = ...@@ -177,6 +177,8 @@ const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
{ {
"mute", "mute",
"volume", "volume",
"track",
"channel",
}; };
const int LibvlcAudioNPObject::propertyCount = sizeof(LibvlcAudioNPObject::propertyNames)/sizeof(NPUTF8 *); const int LibvlcAudioNPObject::propertyCount = sizeof(LibvlcAudioNPObject::propertyNames)/sizeof(NPUTF8 *);
...@@ -185,6 +187,8 @@ enum LibvlcAudioNPObjectPropertyIds ...@@ -185,6 +187,8 @@ enum LibvlcAudioNPObjectPropertyIds
{ {
ID_audio_mute, ID_audio_mute,
ID_audio_volume, ID_audio_volume,
ID_audio_track,
ID_audio_channel,
}; };
RuntimeNPObject::InvokeResult LibvlcAudioNPObject::getProperty(int index, NPVariant &result) RuntimeNPObject::InvokeResult LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
...@@ -221,6 +225,46 @@ RuntimeNPObject::InvokeResult LibvlcAudioNPObject::getProperty(int index, NPVari ...@@ -221,6 +225,46 @@ RuntimeNPObject::InvokeResult LibvlcAudioNPObject::getProperty(int index, NPVari
INT32_TO_NPVARIANT(volume, result); INT32_TO_NPVARIANT(volume, result);
return INVOKERESULT_NO_ERROR; return INVOKERESULT_NO_ERROR;
} }
case ID_audio_track:
{
int track = libvlc_audio_get_track(p_plugin->getVLC(), &ex);
if( libvlc_exception_raised(&ex) )
{
NPN_SetException(this, libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return INVOKERESULT_GENERIC_ERROR;
}
INT32_TO_NPVARIANT(track, result);
return INVOKERESULT_NO_ERROR;
}
case ID_audio_channel:
{
char *channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
if( libvlc_exception_raised(&ex) )
{
NPN_SetException(this, libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return INVOKERESULT_GENERIC_ERROR;
}
if( channel )
{
int len = strlen(channel);
NPUTF8 *retval = (NPUTF8*)NPN_MemAlloc(len);
if( retval )
{
memcpy(retval, channel, len);
STRINGN_TO_NPVARIANT(retval, len, result);
}
else
{
NULL_TO_NPVARIANT(result);
}
free( channel );
channel = NULL;
return INVOKERESULT_NO_ERROR;
}
return INVOKERESULT_NO_SUCH_METHOD;
}
default: default:
; ;
} }
...@@ -266,6 +310,45 @@ RuntimeNPObject::InvokeResult LibvlcAudioNPObject::setProperty(int index, const ...@@ -266,6 +310,45 @@ RuntimeNPObject::InvokeResult LibvlcAudioNPObject::setProperty(int index, const
return INVOKERESULT_NO_ERROR; return INVOKERESULT_NO_ERROR;
} }
return INVOKERESULT_INVALID_VALUE; return INVOKERESULT_INVALID_VALUE;
case ID_audio_track:
if( isNumberValue(value) )
{
libvlc_audio_set_track(p_plugin->getVLC(),
numberValue(value), &ex);
if( libvlc_exception_raised(&ex) )
{
NPN_SetException(this, libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return INVOKERESULT_GENERIC_ERROR;
}
return INVOKERESULT_NO_ERROR;
}
return INVOKERESULT_INVALID_VALUE;
case ID_audio_channel:
{
char *psz_channel = NULL;
if( ! NPVARIANT_IS_STRING(value) )
{
return INVOKERESULT_INVALID_VALUE;
}
psz_channel = stringValue(NPVARIANT_TO_STRING(value));
if( !psz_channel )
return INVOKERESULT_GENERIC_ERROR;
libvlc_audio_set_channel(p_plugin->getVLC(), psz_channel, &ex);
if( psz_channel )
free( psz_channel );
if( libvlc_exception_raised(&ex) )
{
NPN_SetException(this, libvlc_exception_get_message(&ex));
libvlc_exception_clear(&ex);
return INVOKERESULT_GENERIC_ERROR;
}
return INVOKERESULT_NO_ERROR;
}
default: default:
; ;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* $Id$ * $Id$
* *
* Authors: Filippo Carone <filippo@carone.org> * Authors: Filippo Carone <filippo@carone.org>
* Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -90,3 +91,99 @@ void libvlc_audio_set_volume( libvlc_instance_t *p_instance, int i_volume, ...@@ -90,3 +91,99 @@ void libvlc_audio_set_volume( libvlc_instance_t *p_instance, int i_volume,
} }
} }
/*****************************************************************************
* libvlc_audio_get_track : Get the current audio track
*****************************************************************************/
int libvlc_audio_get_track( libvlc_instance_t *p_instance,
libvlc_exception_t *p_e )
{
int i_track = 0;
i_track = var_GetInteger( p_instance->p_libvlc_int, "audio-track" );
return i_track;
}
/*****************************************************************************
* libvlc_audio_set_track : Set the current audio track
*****************************************************************************/
void libvlc_audio_set_track( libvlc_instance_t *p_instance, int i_track,
libvlc_exception_t *p_e )
{
int i_ret = -1;
i_ret = var_SetInteger( p_instance->p_libvlc_int, "audio-track", i_track );
if( i_ret < 0 )
{
libvlc_exception_raise( p_e, "Audio track out of range" );
}
}
/*****************************************************************************
* libvlc_audio_get_channel : Get the current audio channel
*****************************************************************************/
char *libvlc_audio_get_channel( libvlc_instance_t *p_instance,
libvlc_exception_t *p_e )
{
char *psz_channel = NULL;
int i_channel = 0;
i_channel = var_GetInteger( p_instance->p_libvlc_int, "audio-channel" );
switch( i_channel )
{
case AOUT_VAR_CHAN_RSTEREO:
psz_channel = strdup("reverse");
break;
case AOUT_VAR_CHAN_STEREO:
psz_channel = strdup("stereo");
break;
case AOUT_VAR_CHAN_LEFT:
psz_channel = strdup("left");
break;
case AOUT_VAR_CHAN_RIGHT:
psz_channel = strdup("right");
break;
case AOUT_VAR_CHAN_DOLBYS:
psz_channel = strdup("dolby");
break;
default:
psz_channel = strdup("disabled");
break;
}
return psz_channel;
}
/*****************************************************************************
* libvlc_audio_set_channel : Set the current audio channel
*****************************************************************************/
void libvlc_audio_set_channel( libvlc_instance_t *p_instance, char *psz_channel,
libvlc_exception_t *p_e )
{
int i_ret = -1;
int i_channel = 0;
if( !psz_channel )
{
libvlc_exception_raise( p_e, "Audio track out of range" );
}
else
{
if( strncmp( psz_channel, "reverse", 7 ) == 0 )
i_channel = AOUT_VAR_CHAN_RSTEREO;
else if( strncmp( psz_channel, "stereo", 6 ) == 0 )
i_channel = AOUT_VAR_CHAN_STEREO;
else if( strncmp( psz_channel, "left", 4 ) == 0 )
i_channel = AOUT_VAR_CHAN_LEFT;
else if( strncmp( psz_channel, "right", 5 ) == 0 )
i_channel = AOUT_VAR_CHAN_RIGHT;
else if( strncmp( psz_channel, "dolby", 5 ) == 0 )
i_channel = AOUT_VAR_CHAN_DOLBYS;
i_ret = var_SetInteger( p_instance->p_libvlc_int, "audio-channel", i_channel );
if( i_ret < 0 )
{
libvlc_exception_raise( p_e, "Audio track out of range" );
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment