1 /*
2  * pcss.h
3  *
4  * PC Sound System support.
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (c) 2001 Equivalence Pty. Ltd.
10  *
11  * The contents of this file are subject to the Mozilla Public License
12  * Version 1.0 (the "License"); you may not use this file except in
13  * compliance with the License. You may obtain a copy of the License at
14  * http://www.mozilla.org/MPL/
15  *
16  * Software distributed under the License is distributed on an "AS IS"
17  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18  * the License for the specific language governing rights and limitations
19  * under the License.
20  *
21  * The Original Code is Open Phone Abstraction Library.
22  *
23  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24  *
25  * Contributor(s): ______________________________________.
26  *
27  * $Revision: 28276 $
28  * $Author: rjongbloed $
29  * $Date: 2012-08-29 21:50:30 -0500 (Wed, 29 Aug 2012) $
30  */
31 
32 #ifndef OPAL_OPAL_PCSS_H
33 #define OPAL_OPAL_PCSS_H
34 
35 #ifdef P_USE_PRAGMA
36 #pragma interface
37 #endif
38 
39 
40 #include <opal/buildopts.h>
41 
42 #if OPAL_HAS_PCSS
43 
44 #include <ptlib/sound.h>
45 #include <opal/localep.h>
46 
47 
48 class OpalPCSSConnection;
49 
50 
51 /** PC Sound System endpoint.
52  */
53 class OpalPCSSEndPoint : public OpalLocalEndPoint
54 {
55     PCLASSINFO(OpalPCSSEndPoint, OpalLocalEndPoint);
56   public:
57   /**@name Construction */
58   //@{
59     /**Create a new endpoint.
60      */
61     OpalPCSSEndPoint(
62       OpalManager & manager,  ///<  Manager of all endpoints.
63       const char * prefix = "pc" ///<  Prefix for URL style address strings
64     );
65 
66     /**Destroy endpoint.
67      */
68     ~OpalPCSSEndPoint();
69   //@}
70 
71   /**@name Overrides from OpalEndPoint */
72   //@{
73     /**Set up a connection to a remote party.
74        This is called from the OpalManager::MakeConnection() function once
75        it has determined that this is the endpoint for the protocol.
76 
77        The general form for this party parameter is:
78 
79             [proto:][alias@][transport$]address[:port]
80 
81        where the various fields will have meanings specific to the endpoint
82        type. For example, with H.323 it could be "h323:Fred@site.com" which
83        indicates a user Fred at gatekeeper size.com. Whereas for the PSTN
84        endpoint it could be "pstn:5551234" which is to call 5551234 on the
85        first available PSTN line.
86 
87        The proto field is optional when passed to a specific endpoint. If it
88        is present, however, it must agree with the endpoints protocol name or
89        false is returned.
90 
91        This function usually returns almost immediately with the connection
92        continuing to occur in a new background thread.
93 
94        If false is returned then the connection could not be established. For
95        example if a PSTN endpoint is used and the assiciated line is engaged
96        then it may return immediately. Returning a non-NULL value does not
97        mean that the connection will succeed, only that an attempt is being
98        made.
99 
100        The default behaviour is pure.
101      */
102     virtual PSafePtr<OpalConnection> MakeConnection(
103       OpalCall & call,           ///<  Owner of connection
104       const PString & party,     ///<  Remote party to call
105       void * userData = NULL,    ///<  Arbitrary data to pass to connection
106       unsigned options = 0,                    ///< Option bit map to be passed to connection
107       OpalConnection::StringOptions * stringOptions = NULL ///< Options to be passed to connection
108     );
109   //@}
110 
111   /**@name Overrides from OpalLocalEndPoint */
112   //@{
113     /**Call back to indicate that remote is ringing.
114        If false is returned the call is aborted.
115 
116        The default implementation does nothing.
117       */
118     virtual bool OnOutgoingCall(
119       const OpalLocalConnection & connection ///<  Connection having event
120     );
121 
122     /**Call back to indicate that there is an incoming call.
123        Note this function should not block or it will impede the operation of
124        the stack.
125 
126        The default implementation returns true;
127 
128        @return false is returned the call is aborted with status of EndedByLocalBusy.
129 
130       */
131     virtual bool OnIncomingCall(
132       OpalLocalConnection & connection ///<  Connection having event
133     );
134 
135     /**Call back to indicate that the remote user has indicated something.
136        If false is returned the call is aborted.
137 
138        The default implementation does nothing.
139       */
140     virtual bool OnUserInput(
141       const OpalLocalConnection & connection, ///<  Connection having event
142       const PString & indication              ///<  Received user input indications
143     );
144   //@}
145 
146   /**@name Customisation call backs */
147   //@{
148     /**Create a connection for the PCSS endpoint.
149        The default implementation is to create a OpalPCSSConnection.
150       */
151     virtual OpalPCSSConnection * CreateConnection(
152       OpalCall & call,    ///<  Owner of connection
153       const PString & playDevice, ///<  Sound channel play device
154       const PString & recordDevice, ///<  Sound channel record device
155       void * userData,    ///<  Arbitrary data to pass to connection
156       unsigned options,                    ///< Option bit map to be passed to connection
157       OpalConnection::StringOptions * stringOptions ///< Options to be passed to connection
158     );
159 
160     /**Create an PSoundChannel based media stream.
161       */
162     virtual PSoundChannel * CreateSoundChannel(
163       const OpalPCSSConnection & connection, ///<  Connection needing created sound channel
164       const OpalMediaFormat & mediaFormat,   ///<  Media format for the connection
165       PBoolean isSource                          ///<  Direction for channel
166     );
167   //@}
168 
169   /**@name User Interface operations */
170   //@{
171     /**Find a connection that uses the specified token.
172        This searches the endpoint for the connection that contains the token
173        as provided by functions such as MakeConnection(). If not then it
174        attempts to use the token as a OpalCall token and find a connection
175        of the same class.
176       */
177     PSafePtr<OpalPCSSConnection> GetPCSSConnectionWithLock(
178       const PString & token,     ///<  Token to identify connection
179       PSafetyMode mode = PSafeReadWrite ///< Lock mode
180     ) { return GetConnectionWithLockAs<OpalPCSSConnection>(token, mode); }
181 
182     /**Call back to indicate that there is an incoming call.
183        Note this function should not block or it will impede the operation of
184        the stack.
185 
186        The default implementation is pure.
187 
188        @return false is returned the call is aborted with status of EndedByLocalBusy.
189       */
190     virtual PBoolean OnShowIncoming(
191       const OpalPCSSConnection & connection ///<  Connection having event
192     ) = 0;
193 
194     /**Accept the incoming connection.
195        Returns false if the connection token does not correspond to a valid
196        connection.
197       */
198     virtual PBoolean AcceptIncomingConnection(
199       const PString & connectionToken ///<  Token of connection to accept call
200     );
201 
202     /**Reject the incoming connection.
203        Returns false if the connection token does not correspond to a valid
204        connection.
205       */
206     virtual PBoolean RejectIncomingConnection(
207       const PString & connectionToken,       ///<  Token of connection to accept call
208       const OpalConnection::CallEndReason & reason = OpalConnection::EndedByAnswerDenied ///<  Reason for rejecting the call
209     );
210 
211     /**Call back to indicate that remote is ringing.
212        If false is returned the call is aborted.
213 
214        The default implementation is pure.
215       */
216     virtual PBoolean OnShowOutgoing(
217       const OpalPCSSConnection & connection ///<  Connection having event
218     ) = 0;
219 
220     /**Call back to indicate that the remote user has indicated something.
221        If false is returned the call is aborted.
222 
223        The default implementation does nothing.
224       */
225     virtual PBoolean OnShowUserInput(
226       const OpalPCSSConnection & connection, ///<  Connection having event
227       const PString & indication             ///<  Received user input indications
228     );
229   //@}
230 
231   /**@name Member variable access */
232   //@{
233     /**Set the name for the sound channel to be used for output.
234        If the name is not suitable for use with the PSoundChannel class then
235        the function will return false and not change the device.
236 
237        This defaults to the value of the PSoundChannel::GetDefaultDevice()
238        function.
239      */
240     virtual PBoolean SetSoundChannelPlayDevice(const PString & name);
241 
242     /**Get the name for the sound channel to be used for output.
243        This defaults to the value of the PSoundChannel::GetDefaultDevice()
244        function.
245      */
GetSoundChannelPlayDevice()246     const PString & GetSoundChannelPlayDevice() const { return soundChannelPlayDevice; }
247 
248     /**Set the name for the sound channel to be used for input.
249        If the name is not suitable for use with the PSoundChannel class then
250        the function will return false and not change the device.
251 
252        This defaults to the value of the PSoundChannel::GetDefaultDevice()
253        function.
254      */
255     virtual PBoolean SetSoundChannelRecordDevice(const PString & name);
256 
257     /**Get the name for the sound channel to be used for input.
258        This defaults to the value of the PSoundChannel::GetDefaultDevice()
259        function.
260      */
GetSoundChannelRecordDevice()261     const PString & GetSoundChannelRecordDevice() const { return soundChannelRecordDevice; }
262 
263     /**Get default the sound channel buffer depth.
264        Note the largest of the depth in frames and the depth in milliseconds
265        as returned by GetSoundBufferTime() is used.
266       */
GetSoundChannelBufferDepth()267     unsigned GetSoundChannelBufferDepth() const { return soundChannelBuffers; }
268 
269     /**Set the default sound channel buffer depth.
270        Note the largest of the depth in frames and the depth in milliseconds
271        as returned by GetSoundBufferTime() is used.
272       */
273     void SetSoundChannelBufferDepth(
274       unsigned depth    ///<  New depth
275     );
276 
277     /**Get default the sound channel buffer time in milliseconds.
278        Note the largest of the depth in frames and the depth in milliseconds
279        as returned by GetSoundBufferTime() is used.
280       */
GetSoundChannelBufferTime()281     unsigned GetSoundChannelBufferTime() const { return m_soundChannelBufferTime; }
282 
283     /**Set the default sound channel buffer time in milliseconds.
284        Note the largest of the depth in frames and the depth in milliseconds
285        as returned by GetSoundBufferTime() is used.
286       */
287     void SetSoundChannelBufferTime(
288       unsigned depth    ///<  New depth in milliseconds
289     );
290   //@}
291 
292   protected:
293     PString  soundChannelPlayDevice;
294     PString  soundChannelRecordDevice;
295     unsigned soundChannelBuffers;
296     unsigned m_soundChannelBufferTime;
297 
298   private:
299     P_REMOVE_VIRTUAL(OpalPCSSConnection *, CreateConnection(OpalCall &, const PString &, const PString &, void *), 0)
300 };
301 
302 
303 /** PC Sound System connection.
304  */
305 class OpalPCSSConnection : public OpalLocalConnection
306 {
307     PCLASSINFO(OpalPCSSConnection, OpalLocalConnection);
308   public:
309   /**@name Construction */
310   //@{
311     /**Create a new endpoint.
312      */
313     OpalPCSSConnection(
314       OpalCall & call,              ///<  Owner calll for connection
315       OpalPCSSEndPoint & endpoint,  ///<  Owner endpoint for connection
316       const PString & playDevice,   ///<  Sound channel play device
317       const PString & recordDevice,  ///<  Sound channel record device
318       unsigned options = 0,                    ///< Option bit map to be passed to connection
319       OpalConnection::StringOptions * stringOptions = NULL ///< Options to be passed to connection
320     );
321 
322     /**Destroy endpoint.
323      */
324     ~OpalPCSSConnection();
325   //@}
326 
327   /**@name Overrides from OpalConnection */
328   //@{
329     /**Initiate the transfer of an existing call (connection) to a new remote
330        party.
331 
332        If remoteParty is a valid call token, then the remote party is transferred
333        to that party (consultation transfer) and both calls are cleared.
334      */
335     virtual bool TransferConnection(
336       const PString & remoteParty   ///<  Remote party to transfer the existing call to
337     );
338 
339     /**Open a new media stream.
340        This will create a media stream of an appropriate subclass as required
341        by the underlying connection protocol. For instance H.323 would create
342        an OpalRTPStream.
343 
344        The sessionID parameter may not be needed by a particular media stream
345        and may be ignored. In the case of an OpalRTPStream it us used.
346 
347        Note that media streams may be created internally to the underlying
348        protocol. This function is not the only way a stream can come into
349        existance.
350 
351        The default behaviour is pure.
352      */
353     virtual OpalMediaStream * CreateMediaStream(
354       const OpalMediaFormat & mediaFormat, ///<  Media format for stream
355       unsigned sessionID,                  ///<  Session number for stream
356       PBoolean isSource                        ///<  Is a source stream
357     );
358 
359     /**Set  the volume (gain) for the audio media channel.
360        The volume range is 0 == muted, 100 == LOUDEST.
361       */
362     virtual PBoolean SetAudioVolume(
363       PBoolean source,        ///< true for source (microphone), false for sink (speaker)
364       unsigned percentage     ///< Gain, 0=silent, 100=maximun
365     );
366 
367     /**Get  the volume (gain) for the audio media channel.
368        The volume range is 0 == muted, 100 == LOUDEST.
369       */
370     virtual PBoolean GetAudioVolume(
371       PBoolean source,        ///< true for source (microphone), false for sink (speaker)
372       unsigned & percentage   ///< Gain, 0=silent, 100=maximun
373     );
374 
375     /**Set the mute state for the audio media channel.
376       */
377     virtual bool SetAudioMute(
378       bool source,        ///< true for source (microphone), false for sink (speaker)
379       bool mute           ///< Flag for muted audio
380     );
381 
382     /**Get the mute state for the audio media channel.
383       */
384     virtual bool GetAudioMute(
385       bool source,        ///< true for source (microphone), false for sink (speaker)
386       bool & mute         ///< Flag for muted audio
387     );
388 
389     /**Get the average signal level (0..32767) for the audio media channel.
390        A return value of UINT_MAX indicates no valid signal, eg no audio channel opened.
391       */
392     virtual unsigned GetAudioSignalLevel(
393       PBoolean source                   ///< true for source (microphone), false for sink (speaker)
394     );
395   //@}
396 
397   /**@name New operations */
398   //@{
399     /**Create an PSoundChannel based media stream.
400       */
401     virtual PSoundChannel * CreateSoundChannel(
402       const OpalMediaFormat & mediaFormat, ///<  Media format for the connection
403       PBoolean isSource                        ///<  Direction for channel
404     );
405   //@}
406 
407   /**@name Member variable access */
408   //@{
409     /**Get the name for the sound channel to be used for output.
410        This defaults to the value of the PSoundChannel::GetDefaultDevice()
411        function.
412      */
GetSoundChannelPlayDevice()413     const PString & GetSoundChannelPlayDevice() const { return soundChannelPlayDevice; }
414 
415     /**Get the name for the sound channel to be used for input.
416        This defaults to the value of the PSoundChannel::GetDefaultDevice()
417        function.
418      */
GetSoundChannelRecordDevice()419     const PString & GetSoundChannelRecordDevice() const { return soundChannelRecordDevice; }
420 
421     /**Get default the sound channel buffer depth.
422        Note the largest of the depth in frames and the depth in milliseconds
423        as returned by GetSoundBufferTime() is used.
424       */
GetSoundChannelBufferDepth()425     unsigned GetSoundChannelBufferDepth() const { return soundChannelBuffers; }
426 
427     /**Get default the sound channel buffer time in milliseconds.
428        Note the largest of the depth in frames and the depth in milliseconds
429        as returned by GetSoundBufferTime() is used.
430       */
GetSoundChannelBufferTime()431     unsigned GetSoundChannelBufferTime() const { return m_soundChannelBufferTime; }
432   //@}
433 
434 
435   protected:
436     OpalPCSSEndPoint & endpoint;
437     PString            soundChannelPlayDevice;
438     PString            soundChannelRecordDevice;
439     unsigned           soundChannelBuffers;
440     unsigned           m_soundChannelBufferTime;
441 };
442 
443 #else
444 
445 #ifdef _MSC_VER
446 #pragma message("PTLib soundcard support not available")
447 #else
448 #warning "PTLib soundcard support not available"
449 #endif
450 
451 
452 #endif // OPAL_HAS_PCSS
453 
454 #endif // OPAL_OPAL_PCSS_H
455 
456 
457 // End of File ///////////////////////////////////////////////////////////////
458