/// <summary>
        /// Can be called to provide a thread safe way to pass a playback message to the player object.
        /// The events to be performed (eg play, pause, seek) will often be sent to the Server from the iOS device, meaning they will be received on one of the Server's threads. If the server directly accessed the player component, this would not be thread safe and could cause crashes.
        /// This method will check if the request to access player is being called on the right thread, if so it will just perform the requested action, if not it will request that the method be reinvoked (using the sendPlaybackEventCallback) on the correct thread (the same thread that created player, ensuring nobody tries to access player when it isn't available).
        /// </summary>
        /// <param name="action">The action to perform (eg "play", "pause", "stop", "scrub"</param>
        /// <param name="param">Any extra data that might go with that action (eg the seek position). For playURL two pieces of information can be given, the URL then the start position which is a number between 0 and 1, where 0.5 is halfway through the file (in that order)<</param>
        private void sendPlaybackEvent(string action, params string[] parameters)
        {
            //quicktime player
            if (usingQuicktime)
            {
                if (quicktimePlayer.InvokeRequired)//wrong thread, send callback
                {
                    sendPlaybackEventCallback d = new sendPlaybackEventCallback(sendPlaybackEvent);

                    //first prepare the parameters that need to get passed to the callback
                    object[] callbackParams = new object[] { action, parameters };

                    //now invoke the callback with the parameters
                    quicktimePlayer.Invoke(d, callbackParams);
                }
                else //right thread :-)
                {
                    if (action.Equals("pause"))
                    {
                        Debug.WriteLine("pausing player");
                        if (quicktimePlayer.Movie != null)
                        {
                            quicktimePlayer.Movie.Pause();
                        }
                    }
                    else if (action.Equals("play"))
                    {
                        Debug.WriteLine("playing player");
                        if (quicktimePlayer.Movie != null)
                        {
                            quicktimePlayer.Movie.Play();
                        }
                    }
                    else if (action.Equals("stop"))
                    {
                        Debug.WriteLine("stopping player");
                        if (quicktimePlayer.Movie != null)
                        {
                            removeMovieEventListeners(quicktimePlayer.Movie);
                            quicktimePlayer.Movie.Stop();
                        }
                    }
                    else if (action.Equals("scrub"))
                    {
                        if (parameters.Length > 0) //if the scrub position exists in the paramters (should be first arg)...
                        {
                            Debug.WriteLine("scrubbing to position: {0}", parameters[0]);
                            if (quicktimePlayer.Movie != null)
                            {
                                int timescale = quicktimePlayer.Movie.TimeScale; //get the timescale of the file, this will be used to multiply the input time (in seconds) by to get the quicktime time. (quicktime uses these durations instead of seconds like WMP).
                                if (timescale == 0)
                                {
                                    timescale = 1;
                                }
                                quicktimePlayer.Movie.Time = (int)Convert.ToDouble(parameters[0]) * timescale; //could have tried toInt32, but that causes exception when string is a double "3.2453". Also, quicktime seek time is seconds*timescale
                            }
                        }
                    }
                    else if (action.Equals("playUrl"))
                    {
                        if (parameters.Length > 0) //if the playback url exists in the paramters (should be first arg)...
                        {
                            imageToolStripMenuItem.Enabled = false;

                            //TODO: At the moment, m4v files direct from the iDevice aren't supported as I dont know how to pass the PIC request on to quicktime, maybe fix it in future. For now, I have to ignore it.
                            if (parameters[0].Trim().EndsWith("m4v"))
                            {
                                return;
                            }

                            //if the application is minimised to system tray and it isn't set to go fullscreen on playing a file, restore it ready to play the file. If the start video fullscreen option has been chosen, there's no point restoring the window (and people might actually want it left in the system tray, to mean it can be left running all the time without interfering)
                            if (systemTrayIcon.Visible == true && !startVideosFullscreenToolStripMenuItem.Checked)
                            {
                                systemTrayIcon_DoubleClick(this, null);
                            }

                            //remove old listeners
                            removeMovieEventListeners(quicktimePlayer.Movie);

                            //make the right components visible
                            setPictureBoxVisibility(false);
                            setQuicktimePlayerVisibility(true);

                            //set the url and send the loading status message
                            Debug.WriteLine("Quicktime player attempting to play URL" + parameters[0]);
                            quicktimePlayer.URL = parameters[0];
                            theServer.sendStatusMessage("loading");

                            //if a start position was given, seek to it
                            if (parameters.Length > 1 && quicktimePlayer.Movie != null)
                            {
                                double startPosition = Convert.ToDouble(parameters[1]);
                                if (startPosition > 0) //don't bother doing anything if it's just 0
                                {
                                    //the position of the track is the startPosition * total length of track
                                    quicktimePlayer.Movie.Time = (int)(startPosition * quicktimePlayer.Movie.EndTime);
                                }
                            }

                            if (quicktimePlayer.Movie != null)
                            {
                                videoHasAlreadyBeenStarted = false; //new video started, so set this to false.
                                addMovieEventListeners(quicktimePlayer.Movie);
                                quicktimePlayer.Movie.Play();
                            }
                        }
                    }
                }
            }
            else
            {
                if (player.InvokeRequired) //wrong thread, send callback
                {
                    sendPlaybackEventCallback d = new sendPlaybackEventCallback(sendPlaybackEvent);

                    //first prepare the parameters that need to get passed to the callback
                    object[] callbackParams = new object[] { action, parameters };

                    //now invoke the callback with the parameters
                    player.Invoke(d, callbackParams);
                }
                else //right thread :-)
                {
                    if (action.Equals("pause"))
                    {
                        Debug.WriteLine("pausing player");
                        player.Ctlcontrols.pause();
                    }
                    else if (action.Equals("play"))
                    {
                        Debug.WriteLine("playing player");
                        player.Ctlcontrols.play();
                    }
                    else if (action.Equals("stop"))
                    {
                        Debug.WriteLine("stopping player");
                        player.Ctlcontrols.stop();
                    }
                    else if (action.Equals("scrub"))
                    {
                        if (parameters.Length > 0)//if the scrub position exists in the paramters (should be first arg)...
                        {
                            player.Ctlcontrols.currentPosition = Convert.ToDouble(parameters[0]);
                        }
                    }
                    else if (action.Equals("playUrl"))
                    {
                        if (parameters.Length > 0)//if the playback url exists in the paramters (should be first arg)...
                        {
                            imageToolStripMenuItem.Enabled = false;

                            //TODO: At the moment, m4v files direct from the iDevice aren't supported as I dont know how to pass the PIC request on to quicktime, maybe fix it in future. For now, I have to ignore it.
                            if (parameters[0].Trim().EndsWith("m4v"))
                            {
                                return;
                            }

                            //if the application is minimised to system tray and it isn't set to go fullscreen on playing a file, restore it ready to play the file. If the start video fullscreen option has been chosen, there's no point restoring the window (and people might actually want it left in the system tray, to mean it can be left running all the time without interfering)
                            if (systemTrayIcon.Visible == true && !startVideosFullscreenToolStripMenuItem.Checked)
                            {
                                systemTrayIcon_DoubleClick(this, null);
                            }

                            //make the right component visible
                            setPictureBoxVisibility(false);
                            setPlayerVisibility(true);

                            //set the url and send the loading status message
                            player.URL = parameters[0];
                            theServer.sendStatusMessage("loading");

                            videoHasAlreadyBeenStarted = false; //new video started loading, so set this to false.

                            //if a start position was given, seek to it
                            if (parameters.Length > 1)
                            {
                                double startPosition = Convert.ToDouble(parameters[1]);
                                if (startPosition > 0) //don't bother doing anything if it's just 0
                                {
                                    player.Ctlcontrols.currentPosition = player.currentMedia.duration * startPosition; //FIXME: fix this, as WMP always returns 0 as the duration when it's loading, so skipping to the correct position doesn't work.
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Can be called to provide a thread safe way to pass a playback message to the player object.
        /// The events to be performed (eg play, pause, seek) will often be sent to the Server from the iOS device, meaning they will be received on one of the Server's threads. If the server directly accessed the player component, this would not be thread safe and could cause crashes.
        /// This method will check if the request to access player is being called on the right thread, if so it will just perform the requested action, if not it will request that the method be reinvoked (using the sendPlaybackEventCallback) on the correct thread (the same thread that created player, ensuring nobody tries to access player when it isn't available).
        /// </summary>
        /// <param name="action">The action to perform (eg "play", "pause", "stop", "scrub"</param>
        /// <param name="param">Any extra data that might go with that action (eg the seek position). For playURL two pieces of information can be given, the URL then the start position which is a number between 0 and 1, where 0.5 is halfway through the file (in that order)<</param>
        private void sendPlaybackEvent(string action, params string[] parameters)
        {
            //quicktime player
            if (usingQuicktime)
            {
                if (quicktimePlayer.InvokeRequired)//wrong thread, send callback
                {
                    sendPlaybackEventCallback d = new sendPlaybackEventCallback(sendPlaybackEvent);

                    //first prepare the parameters that need to get passed to the callback
                    object[] callbackParams = new object[] { action, parameters };

                    //now invoke the callback with the parameters
                    quicktimePlayer.Invoke(d, callbackParams);
                }
                else //right thread :-)
                {
                    if (action.Equals("pause"))
                    {
                        Debug.WriteLine("pausing player");
                        if (quicktimePlayer.Movie != null)
                        {
                            quicktimePlayer.Movie.Pause();
                        }
                    }
                    else if (action.Equals("play"))
                    {
                        Debug.WriteLine("playing player");
                        if (quicktimePlayer.Movie != null)
                        {
                            quicktimePlayer.Movie.Play();
                        }
                    }
                    else if (action.Equals("stop"))
                    {
                        Debug.WriteLine("stopping player");
                        if (quicktimePlayer.Movie != null)
                        {
                            removeMovieEventListeners(quicktimePlayer.Movie);
                            quicktimePlayer.Movie.Stop();
                        }
                    }
                    else if (action.Equals("scrub"))
                    {
                        if (parameters.Length > 0) //if the scrub position exists in the paramters (should be first arg)...
                        {
                            Debug.WriteLine("scrubbing to position: {0}", parameters[0]);
                            if (quicktimePlayer.Movie != null)
                            {
                                int timescale = quicktimePlayer.Movie.TimeScale; //get the timescale of the file, this will be used to multiply the input time (in seconds) by to get the quicktime time. (quicktime uses these durations instead of seconds like WMP).
                                if (timescale == 0)
                                {
                                    timescale = 1;
                                }
                                quicktimePlayer.Movie.Time = (int)Convert.ToDouble(parameters[0]) * timescale; //could have tried toInt32, but that causes exception when string is a double "3.2453". Also, quicktime seek time is seconds*timescale
                            }
                        }
                    }
                    else if (action.Equals("playUrl"))
                    {
                        if (parameters.Length > 0) //if the playback url exists in the paramters (should be first arg)...
                        {
                            imageToolStripMenuItem.Enabled = false;

                            //TODO: At the moment, m4v files direct from the iDevice aren't supported as I dont know how to pass the PIC request on to quicktime, maybe fix it in future. For now, I have to ignore it.
                            if (parameters[0].Trim().EndsWith("m4v"))
                            {
                                return;
                            }

                            //if the application is minimised to system tray and it isn't set to go fullscreen on playing a file, restore it ready to play the file. If the start video fullscreen option has been chosen, there's no point restoring the window (and people might actually want it left in the system tray, to mean it can be left running all the time without interfering)
                            if (systemTrayIcon.Visible == true && !startVideosFullscreenToolStripMenuItem.Checked)
                            {
                                systemTrayIcon_DoubleClick(this, null);
                            }

                            //remove old listeners
                            removeMovieEventListeners(quicktimePlayer.Movie);

                            //make the right components visible
                            setPictureBoxVisibility(false);
                            setQuicktimePlayerVisibility(true);


                            //set the url and send the loading status message
                            Debug.WriteLine("Quicktime player attempting to play URL" + parameters[0]);
                            quicktimePlayer.URL = parameters[0];
                            theServer.sendStatusMessage("loading");

                            //if a start position was given, seek to it
                            if (parameters.Length > 1 && quicktimePlayer.Movie != null)
                            {
                                double startPosition = Convert.ToDouble(parameters[1]);
                                if (startPosition > 0) //don't bother doing anything if it's just 0
                                {
                                    //the position of the track is the startPosition * total length of track
                                    quicktimePlayer.Movie.Time = (int)(startPosition * quicktimePlayer.Movie.EndTime);
                                }
                            }


                            if (quicktimePlayer.Movie != null)
                            {
                                videoHasAlreadyBeenStarted = false; //new video started, so set this to false.
                                addMovieEventListeners(quicktimePlayer.Movie);
                                quicktimePlayer.Movie.Play();
                            }
                        }
                    }
                }
            }
            else
            {
                if (player.InvokeRequired) //wrong thread, send callback
                {
                    sendPlaybackEventCallback d = new sendPlaybackEventCallback(sendPlaybackEvent);

                    //first prepare the parameters that need to get passed to the callback
                    object[] callbackParams = new object[] { action, parameters };

                    //now invoke the callback with the parameters
                    player.Invoke(d, callbackParams);
                }
                else //right thread :-)
                {
                    if (action.Equals("pause"))
                    {
                        Debug.WriteLine("pausing player");
                        player.Ctlcontrols.pause();
                    }
                    else if (action.Equals("play"))
                    {
                        Debug.WriteLine("playing player");
                        player.Ctlcontrols.play();
                    }
                    else if (action.Equals("stop"))
                    {
                        Debug.WriteLine("stopping player");
                        player.Ctlcontrols.stop();
                    }
                    else if (action.Equals("scrub"))
                    {
                        if (parameters.Length > 0)//if the scrub position exists in the paramters (should be first arg)...
                        {
                            player.Ctlcontrols.currentPosition = Convert.ToDouble(parameters[0]);
                        }
                    }
                    else if (action.Equals("playUrl"))
                    {
                        if (parameters.Length > 0)//if the playback url exists in the paramters (should be first arg)...
                        {
                            imageToolStripMenuItem.Enabled = false;

                            //TODO: At the moment, m4v files direct from the iDevice aren't supported as I dont know how to pass the PIC request on to quicktime, maybe fix it in future. For now, I have to ignore it.
                            if (parameters[0].Trim().EndsWith("m4v"))
                            {
                                return;
                            }

                            //if the application is minimised to system tray and it isn't set to go fullscreen on playing a file, restore it ready to play the file. If the start video fullscreen option has been chosen, there's no point restoring the window (and people might actually want it left in the system tray, to mean it can be left running all the time without interfering)
                            if (systemTrayIcon.Visible == true && !startVideosFullscreenToolStripMenuItem.Checked)
                            {
                                systemTrayIcon_DoubleClick(this, null);
                            }

                            //make the right component visible
                            setPictureBoxVisibility(false);
                            setPlayerVisibility(true);

                            //set the url and send the loading status message
                            player.URL = parameters[0];
                            theServer.sendStatusMessage("loading");

                            videoHasAlreadyBeenStarted = false; //new video started loading, so set this to false.

                            //if a start position was given, seek to it
                            if (parameters.Length > 1)
                            {
                                double startPosition = Convert.ToDouble(parameters[1]);
                                if (startPosition > 0)                                                                 //don't bother doing anything if it's just 0
                                {
                                    player.Ctlcontrols.currentPosition = player.currentMedia.duration * startPosition; //FIXME: fix this, as WMP always returns 0 as the duration when it's loading, so skipping to the correct position doesn't work.
                                }
                            }
                        }
                    }
                }
            }
        }