/// <summary>
        /// Returns the status of the channel.<br/>
        /// Return values:
        /// <ul>
        /// <li>0 Channel is down and available</li>
        /// <li>1 Channel is down, but reserved</li>
        /// <li>2 Channel is off hook</li>
        /// <li>3 Digits (or equivalent) have been dialed</li>
        /// <li>4 Line is ringing</li>
        /// <li>5 Remote end is ringing</li>
        /// <li>6 Line is up</li>
        /// <li>7 Line is busy</li>
        /// </ul>
        /// </summary>
        /// <returns> the status of the channel.
        /// </returns>
        protected internal int GetChannelStatus()
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.ChannelStatusCommand());
            return(channel.LastReply.ResultCode);
        }
        /// <summary>
        /// Record to a file until a given dtmf digit in the sequence is received.<br/>
        /// Returns -1 on hangup or error.<br/>
        /// The format will specify what kind of file will be recorded. The timeout is
        /// the maximum record time in milliseconds, or -1 for no timeout. Offset samples
        /// is optional, and if provided will seek to the offset without exceeding the
        /// end of the file. "maxSilence" is the number of seconds of maxSilence allowed
        /// before the function returns despite the lack of dtmf digits or reaching
        /// timeout.
        /// </summary>
        /// <param name="file">the name of the file to stream, must not include extension.</param>
        /// <param name="format">the format of the file to be recorded, for example "wav".</param>
        /// <param name="escapeDigits">contains the digits that allow the user to end recording.</param>
        /// <param name="timeout">the maximum record time in milliseconds, or -1 for no timeout.</param>
        /// <param name="offset">the offset samples to skip.</param>
        /// <param name="beep">true if a beep should be played before recording.</param>
        /// <param name="maxSilence">The amount of silence (in seconds) to allow before returning despite the lack of dtmf digits or reaching timeout.</param>
        /// <returns>result code</returns>
        protected internal int RecordFile(string file, string format, string escapeDigits, int timeout, int offset, bool beep, int maxSilence)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.RecordFileCommand(file, format, escapeDigits, timeout, offset, beep, maxSilence));
            return(channel.LastReply.ResultCode);
        }
Beispiel #3
0
        /// <summary>
        /// Says the given number, returning early if any of the given DTMF number
        /// are received on the channel.
        /// </summary>
        /// <param name="digits">the digit string to say.</param>
        /// <param name="escapeDigits">a String containing the DTMF digits that allow the user to escape.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char SayDigits(string digits, string escapeDigits)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.SayDigitsCommand(digits, escapeDigits));

            return(lastReply.ResultCodeAsChar);
        }
Beispiel #4
0
        /// <summary>
        /// Plays the given file and allows the user to escape by pressing one of the given digit.
        /// </summary>
        /// <param name="file">name of the file to play.</param>
        /// <param name="escapeDigits">a String containing the DTMF digits that allow the user to escape.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char StreamFile(string file, string escapeDigits)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.StreamFileCommand(file, escapeDigits));

            return(lastReply.ResultCodeAsChar);
        }
Beispiel #5
0
        /// <summary>
        /// Says the given character string with phonetics, returning early if any of
        /// the given DTMF number are received on the channel.
        /// </summary>
        /// <param name="text">the text to say.</param>
        /// <param name="escapeDigits">a String containing the DTMF digits that allow the user to escape.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char SayPhonetic(string text, string escapeDigits)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.SayPhoneticCommand(text, escapeDigits));

            return(lastReply.ResultCodeAsChar);
        }
Beispiel #6
0
        /// <summary>
        /// Executes the given command.
        /// </summary>
        /// <param name="application">the name of the application to execute, for example "Dial".</param>
        /// <returns> the return code of the application of -2 if the application was not found.</returns>
        protected internal int Exec(string application)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.ExecCommand(application));

            return(lastReply.ResultCode);
        }
        /// <summary>
        /// Plays the given file, allowing playback to be interrupted by the given
        /// digits, if any, and allows the listner to control the stream.<br/>
        /// If offset is provided then the audio will seek to sample offset before play
        /// starts.<br/>
        /// Returns 0 if playback completes without a digit being pressed, or the ASCII
        /// numerical value of the digit if one was pressed, or -1 on error or if the
        /// channel was disconnected. <br/>
        /// Remember, the file extension must not be included in the filename.<br/>
        /// Available since Asterisk 1.2
        /// </summary>
        /// <seealso cref="Command.ControlStreamFileCommand"/>
        /// <param name="file">the name of the file to stream, must not include extension.</param>
        /// <param name="escapeDigits">contains the digits that allow the user to interrupt this command.</param>
        /// <returns>result code</returns>
        protected internal int ControlStreamFile(string file, string escapeDigits)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits));
            return(channel.LastReply.ResultCode);
        }
        /// <summary>
        /// Plays the given file and waits for the user to enter DTMF digits until he
        /// presses '#'. The user may interrupt the streaming by starting to enter
        /// digits.
        /// </summary>
        /// <param name="file">the name of the file to play</param>
        /// <returns> a String containing the DTMF the user entered</returns>
        protected internal string GetData(string file)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.GetDataCommand(file));
            return(channel.LastReply.GetResult());
        }
        /// <summary>
        /// Says the given character string, returning early if any of the given DTMF
        /// number are received on the channel.
        /// </summary>
        /// <param name="text">the text to say.</param>
        /// <param name="escapeDigits">a String containing the DTMF digits that allow the user to escape.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char SayAlpha(string text, string escapeDigits)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.SayAlphaCommand(text, escapeDigits));
            return(channel.LastReply.ResultCodeAsChar);
        }
        /// <summary>
        /// Says the given time in the given format and timezone and allows interruption by one of the given escape digits.<br/>
        /// Available since Asterisk 1.2.
        /// </summary>
        /// <param name="time">the time to say in seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC)</param>
        /// <param name="escapeDigits">the digits that allow the user to interrupt this command or null for none.</param>
        /// <param name="format">the format the time should be said in</param>
        /// <param name="timezone">the timezone to use when saying the time, for example "UTC" or "Europe/Berlin".</param>
        /// <returns>the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char SayDateTime(long time, string escapeDigits, string format, string timezone)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits, format, timezone));
            return(channel.LastReply.ResultCodeAsChar);
        }
        /// <summary>
        /// Waits up to 'timeout' milliseconds to receive a DTMF digit.
        /// </summary>
        /// <param name="timeout">timeout the milliseconds to wait for the channel to receive a DTMF digit, -1 will wait forever.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char WaitForDigit(int timeout)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.WaitForDigitCommand(timeout));
            return(channel.LastReply.ResultCodeAsChar);
        }
        /// <summary>
        /// Executes the given command.
        /// </summary>
        /// <param name="application">the name of the application to execute, for example "Dial".</param>
        /// <param name="options">the parameters to pass to the application, for example "SIP/123".</param>
        /// <returns> the return code of the application of -2 if the application was not found.</returns>
        protected internal int Exec(string application, string options)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.ExecCommand(application, options));
            return(channel.LastReply.ResultCode);
        }
        /// <summary>
        /// Says the given number, returning early if any of the given DTMF number
        /// are received on the channel.
        /// </summary>
        /// <param name="number">the number to say.</param>
        /// <param name="escapeDigits">a String containing the DTMF digits that allow the user to escape.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char SayNumber(string number, string escapeDigits)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.SayNumberCommand(number, escapeDigits));
            return(channel.LastReply.ResultCodeAsChar);
        }
        /// <summary>
        /// Plays the given file and waits for the user to enter DTMF digits until he
        /// presses '#' or the timeout occurs or the maximum number of digits has
        /// been entered. The user may interrupt the streaming by starting to enter
        /// digits.
        /// </summary>
        /// <param name="file">the name of the file to play</param>
        /// <param name="timeout">the timeout in milliseconds to wait for user input.<br/>
        /// 0 means standard timeout value, -1 means "ludicrous time"
        /// (essentially never times out).</param>
        /// <param name="maxDigits">the maximum number of digits the user is allowed to enter</param>
        /// <returns> a String containing the DTMF the user entered</returns>
        protected internal string GetData(string file, long timeout, int maxDigits)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.GetDataCommand(file, timeout, maxDigits));
            return(channel.LastReply.GetResult());
        }
        /// <summary>
        /// Plays the given file, and waits for the user to press one of the given
        /// digits. If none of the esacpe digits is pressed while streaming the file
        /// it waits for the specified timeout still waiting for the user to press a
        /// digit.
        /// </summary>
        /// <param name="file">the name of the file to stream, must not include extension.</param>
        /// <param name="escapeDigits">contains the digits that the user is expected to press.</param>
        /// <param name="timeout">the timeout in seconds to wait if none of the defined esacpe digits was presses while streaming.</param>
        /// <returns> the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char GetOption(string file, string escapeDigits, int timeout)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.GetOptionCommand(file, escapeDigits, timeout));
            return(channel.LastReply.ResultCodeAsChar);
        }
        /// <summary>
        /// Record to a file until a given dtmf digit in the sequence is received.<br/>
        /// Returns -1 on hangup or error.<br/>
        /// The format will specify what kind of file will be recorded. The timeout is
        /// the maximum record time in milliseconds, or -1 for no timeout. Offset samples
        /// is optional, and if provided will seek to the offset without exceeding the
        /// end of the file. "maxSilence" is the number of seconds of maxSilence allowed
        /// before the function returns despite the lack of dtmf digits or reaching
        /// timeout.
        /// </summary>
        /// <param name="file">the name of the file to stream, must not include extension.</param>
        /// <param name="format">the format of the file to be recorded, for example "wav".</param>
        /// <param name="escapeDigits">contains the digits that allow the user to end recording.</param>
        /// <param name="timeout">the maximum record time in milliseconds, or -1 for no timeout.</param>
        /// <returns>result code</returns>
        protected internal int RecordFile(string file, string format, string escapeDigits, int timeout)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.RecordFileCommand(file, format, escapeDigits, timeout));
            return(channel.LastReply.ResultCode);
        }
Beispiel #17
0
        /// <summary>
        /// Plays the given file and waits for the user to enter DTMF digits until he
        /// presses '#' or the timeout occurs. The user may interrupt the streaming
        /// by starting to enter digits.
        /// </summary>
        /// <param name="file">the name of the file to play</param>
        /// <param name="timeout">the timeout in milliseconds to wait for user input.<br/>
        /// 0 means standard timeout value, -1 means "ludicrous time"
        /// (essentially never times out).</param>
        /// <returns> a String containing the DTMF the user entered</returns>
        protected internal string GetData(string file, long timeout)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.GetDataCommand(file, timeout));

            return(lastReply.GetResult());
        }
Beispiel #18
0
        /// <summary>
        /// Plays the given file, allowing playback to be interrupted by the given
        /// digits, if any, and allows the listner to control the stream.<br/>
        /// If offset is provided then the audio will seek to sample offset before play
        /// starts.<br/>
        /// Returns 0 if playback completes without a digit being pressed, or the ASCII
        /// numerical value of the digit if one was pressed, or -1 on error or if the
        /// channel was disconnected. <br/>
        /// Remember, the file extension must not be included in the filename.<br/>
        /// Available since Asterisk 1.2
        /// </summary>
        /// <seealso cref="Command.ControlStreamFileCommand"/>
        /// <param name="file">the name of the file to stream, must not include extension.</param>
        /// <param name="escapeDigits">contains the digits that allow the user to interrupt this command.</param>
        /// <param name="offset">the offset samples to skip before streaming.</param>
        /// <param name="forwardDigit">the digit for fast forward.</param>
        /// <param name="rewindDigit">the digit for rewind.</param>
        /// <param name="pauseDigit">the digit for pause and unpause.</param>
        /// <returns>result code</returns>
        protected internal int ControlStreamFile(string file, string escapeDigits, int offset, string forwardDigit, string rewindDigit, string pauseDigit)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits, offset, forwardDigit, rewindDigit, pauseDigit));

            return(lastReply.ResultCode);
        }
Beispiel #19
0
        /// <summary>
        /// Plays the given file, allowing playback to be interrupted by the given
        /// digits, if any, and allows the listner to control the stream.<br/>
        /// If offset is provided then the audio will seek to sample offset before play
        /// starts.<br/>
        /// Returns 0 if playback completes without a digit being pressed, or the ASCII
        /// numerical value of the digit if one was pressed, or -1 on error or if the
        /// channel was disconnected. <br/>
        /// Remember, the file extension must not be included in the filename.<br/>
        /// Available since Asterisk 1.2
        /// </summary>
        /// <seealso cref="Command.ControlStreamFileCommand"/>
        /// <param name="file">the name of the file to stream, must not include extension.</param>
        /// <returns>result code</returns>
        protected internal int ControlStreamFile(string file)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.ControlStreamFileCommand(file));

            return(lastReply.ResultCode);
        }
Beispiel #20
0
        /// <summary>
        /// Says the given time and allows interruption by one of the given escape digits.<br/>
        /// Available since Asterisk 1.2.
        /// </summary>
        /// <param name="time">the time to say in seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC)</param>
        /// <param name="escapeDigits">the digits that allow the user to interrupt this command or null for none.</param>
        /// <returns>the DTMF digit pressed or 0x0 if none was pressed.</returns>
        protected internal char SayDateTime(long time, string escapeDigits)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits));

            return(lastReply.ResultCodeAsChar);
        }
        /// <summary>
        /// Retrieves an entry in the Asterisk database for a given family and key.
        /// </summary>
        /// <param name="family">the family of the entry to retrieve.</param>
        /// <param name="key">key the key of the entry to retrieve.</param>
        /// <return>the value of the given family and key or null if there is no such value.</return>
        protected internal string DatabaseGet(string family, string key)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.DatabaseGetCommand(family, key));
            if (channel.LastReply.ResultCode != 1)
            {
                return(null);
            }
            return(channel.LastReply.Extra);
        }
        /// <summary>
        /// Returns the value of the given channel variable.<br/>
        /// Available since Asterisk 1.2.
        /// </summary>
        /// <param name="name">the name of the variable to retrieve.</param>
        /// <param name="channel">the name of the channel.</param>
        /// <returns>the value of the given variable or null if not set.</returns>
        protected internal string GetFullVariable(string name, string channelName)
        {
            AGIChannel channel = this.Channel;

            channel.SendCommand(new Command.GetFullVariableCommand(name, channelName));
            if (channel.LastReply.ResultCode != 1)
            {
                return(null);
            }
            return(channel.LastReply.Extra);
        }
Beispiel #23
0
        /// <summary>
        /// Returns the value of the given channel variable.
        /// </summary>
        /// <param name="name">the name of the variable to retrieve.</param>
        /// <returns> the value of the given variable or null if not set.</returns>
        protected internal string GetVariable(string name)
        {
            AGIChannel channel   = this.Channel;
            AGIReply   lastReply = channel.SendCommand(new Command.GetVariableCommand(name));

            if (lastReply.ResultCode != 1)
            {
                return(null);
            }
            return(lastReply.Extra);
        }
        public void Run()
        {
            try
            {
                var        reader = new AGIReader(socket);
                var        writer = new AGIWriter(socket);
                AGIRequest request;
                using (var enlarger = new SocketConnectionTimeoutEnlarger(socket, 500))
                    request = reader.ReadRequest();

                //Added check for when the request is empty
                //eg. telnet to the service
                if (request.Request.Count > 0)
                {
                    var       channel = new AGIChannel(writer, reader, _SC511_CAUSES_EXCEPTION, _SCHANGUP_CAUSES_EXCEPTION);
                    AGIScript script  = mappingStrategy.DetermineScript(request);
                    Thread.SetData(_channel, channel);

                    if (script != null)
                    {
                        #if LOGGER
                        logger.Info("Begin AGIScript " + script.GetType().FullName + " on " + Thread.CurrentThread.Name);
                        #endif
                        script.Service(request, channel);
                        #if LOGGER
                        logger.Info("End AGIScript " + script.GetType().FullName + " on " + Thread.CurrentThread.Name);
                        #endif
                    }
                    else
                    {
                        var error = "No script configured for URL '" + request.RequestURL + "' (script '" + request.Script +
                                    "')";
                        channel.SendCommand(new VerboseCommand(error, 1));
                        #if LOGGER
                        logger.Error(error);
                        #endif
                    }
                }
                else
                {
                    var error = "A connection was made with no requests";
                    #if LOGGER
                    logger.Error(error);
                    #endif
                }
            }
            catch (AGIHangupException)
            {
            }
            catch (IOException)
            {
            }
            catch (AGIException ex)
            {
                #if LOGGER
                logger.Error("AGIException while handling request", ex);
                #else
                throw ex;
                #endif
            }
            catch (Exception ex)
            {
                #if LOGGER
                logger.Error("Unexpected Exception while handling request", ex);
                #else
                throw ex;
                #endif
            }

            Thread.SetData(_channel, null);
            try
            {
                socket.Close();
            }
            #if LOGGER
            catch (IOException ex)
            {
                logger.Error("Error on close socket", ex);
            }
            #else
            catch { }
            #endif
        }
        public void Run()
        {
            try
            {
                var reader = new AGIReader(socket);
                var writer = new AGIWriter(socket);
                AGIRequest request = reader.ReadRequest();
                var channel = new AGIChannel(writer, reader, _SC511_CAUSES_EXCEPTION, _SCHANGUP_CAUSES_EXCEPTION);
                AGIScript script = mappingStrategy.DetermineScript(request);
                Thread.SetData(_channel, channel);

                if (script != null)
                {
#if LOGGER
                    logger.Info("Begin AGIScript " + script.GetType().FullName + " on " + Thread.CurrentThread.Name);
#endif
                    script.Service(request, channel);
#if LOGGER
                    logger.Info("End AGIScript " + script.GetType().FullName + " on " + Thread.CurrentThread.Name);
#endif
                }
                else
                {
                    var error = "No script configured for URL '" + request.RequestURL + "' (script '" + request.Script +
                                "')";
                    channel.SendCommand(new VerboseCommand(error, 1));
#if LOGGER
                    logger.Error(error);
#endif
                }
            }
            catch (AGIHangupException)
            {
            }
            catch (IOException)
            {
            }
            catch (AGIException ex)
            {
#if LOGGER
                logger.Error("AGIException while handling request", ex);
#else
				throw ex;
#endif
            }
            catch (Exception ex)
            {
#if LOGGER
                logger.Error("Unexpected Exception while handling request", ex);
#else
				throw ex;
#endif
            }

            Thread.SetData(_channel, null);
            try
            {
                socket.Close();
            }
#if LOGGER
            catch (IOException ex)
            {
                logger.Error("Error on close socket", ex);
            }
#else
			catch { }
#endif
        }
Beispiel #26
0
		/*
		 * Call -> play "wellcome" -> wait digit 5 seconds -> press 1 -> play "press-1" -> wait digit -> press * ----------------------------\
		 *               ^                    ^                                                 ^     -> press 4 -> play "press-4" -------\  |
		 *               |                    |                                                 |     -> press any -> play "bad" "digit" -+  |
		 *               |                    |                                                 \-----------------------------------------/  |
		 *               |                    |                                                       -> press # or timeout -\               |
		 *               |                    |                                                                              |               |
		 *               |                    |            -> press # or timeout -> play "goodbye" -> Hangup                 |               |
		 *               |                    |                                          ^                                   |               |
		 *               |                    |                                          \-----------------------------------+               |
		 *               |                    |                                                                              |               |
		 *               |                    |                                                                              |               |
		 *               |                    |           -> press 2 -> play "press-1" -> wait digit  -> press # or timeout -/               |
		 *               |                    |                                                 ^     -> press * ----------------------------+
		 *               |                    |                                                 |     -> press 4 -> play "press-4" -------\  |
		 *               |                    |                                                 |     -> press any -> play "bad" "digit" -+  |
		 *               |                    |                                                 \-----------------------------------------/  |
		 *               |                    |                                                                                              |
		 *               |                    |            -> press other -> play "bad" "digit" -\                                           |
		 *               |                    \--------------------------------------------------/                                           |
		 *               \-------------------------------------------------------------------------------------------------------------------/
		 */

		public override void Service(AGIRequest request, AGIChannel channel)
		{
			Answer();
			int submenu = 0;
			char key = '\0';
			bool welcome = true;

			while (true)
			{
				if (welcome)
				{
					key = StreamFile("welcome", escapeKeys);
					welcome = false;
					submenu = 0;
				}
				if (key == '\0')
				{
					key = WaitForDigit(5000);
					if (key == '\0' || key == '#')
					{
						StreamFile("goodbye");
						break;
					}
				}
				char newKey = '\0';
				switch (submenu)
				{
					case 0:
						switch (key)
						{
							case '1':
								newKey = StreamFile("press-1", escapeKeys);
								submenu = 1;
								break;
							case '2':
								newKey = StreamFile("press-2", escapeKeys);
								submenu = 2;
								break;
							case '3':
								newKey = StreamFile("press-3", escapeKeys);
								break;
							default:
								newKey = StreamFile("bad", escapeKeys);
								if(newKey == '\0')
									newKey = StreamFile("digit", escapeKeys);
								break;
						}
						break;
					case 1:
						switch (key)
						{
							case '*':
								welcome = true;
								break;
							case '4':
								newKey = StreamFile("press-4", escapeKeys);
								break;
							default:
								newKey = StreamFile("bad", escapeKeys);
								if (newKey == '\0')
									newKey = StreamFile("digit", escapeKeys);
								break;
						}
						break;
					case 2:
						switch (key)
						{
							case '*':
								welcome = true;
								break;
							case '5':
								newKey = StreamFile("press-5", escapeKeys);
								break;
							default:
								newKey = StreamFile("bad", escapeKeys);
								if (newKey == '\0')
									newKey = StreamFile("digit", escapeKeys);
								break;
						}
						break;
				}
				key = newKey;
			}
			Hangup();
		}
 public abstract void Service(AGIRequest param1, AGIChannel param2);
Beispiel #28
0
		public abstract void Service(AGIRequest param1, AGIChannel param2);