1// -------------------------------------------------------------------------- 2// Name: sndesd.cpp 3// Purpose: 4// Date: 08/11/1999 5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999 6// CVSID: $Id: sndesd.cpp 35650 2005-09-23 12:56:45Z MR $ 7// wxWindows licence 8// -------------------------------------------------------------------------- 9 10#include "wx/wxprec.h" 11 12#ifndef WX_PRECOMP 13 #include "wx/defs.h" 14 #include "wx/string.h" 15#endif 16 17#ifdef __BORLANDC__ 18 #pragma hdrstop 19#endif 20 21// -------------------------------------------------------------------------- 22// MMedia headers 23// -------------------------------------------------------------------------- 24 25#include "wx/mmedia/sndbase.h" 26#include "wx/mmedia/sndesd.h" 27#include "wx/mmedia/sndpcm.h" 28 29// -------------------------------------------------------------------------- 30// System headers 31// -------------------------------------------------------------------------- 32 33#ifdef HAVE_ESD_H 34#include <sys/types.h> 35#include <sys/stat.h> 36#include <unistd.h> 37#include <esd.h> 38#ifdef __WXGTK__ 39#include <gdk/gdk.h> 40#endif 41#endif 42 43// -------------------------------------------------------------------------- 44 45#define MY_ESD_NAME "wxWidgets/wxSoundStreamESD" 46 47// -------------------------------------------------------------------------- 48// wxSoundStreamESD: ESD sound driver 49 50// -------------------------------------------------------------------------- 51// Constructors/Destructors 52// -------------------------------------------------------------------------- 53 54wxSoundStreamESD::wxSoundStreamESD(const wxString& hostname) 55{ 56#ifndef HAVE_ESD_H 57 m_snderror = wxSOUND_INVDEV; 58 return; 59#else 60 wxSoundFormatPcm pcm_default; 61 62 // First, we make some basic test: is there ESD on this computer ? 63 m_esd_ok = false; 64 65 if (hostname.IsNull()) 66 m_fd_output = esd_play_stream(ESD_PLAY | ESD_STREAM, 22050, 67 hostname.mb_str(), MY_ESD_NAME); 68 else 69 m_fd_output = esd_play_stream(ESD_PLAY | ESD_STREAM, 22050, 70 NULL, MY_ESD_NAME); 71 if (m_fd_output == -1) { 72 // Answer: no. We return with an error. 73 m_snderror = wxSOUND_INVDEV; 74 return; 75 } 76 77 // Close this unuseful stream. 78 esd_close(m_fd_output); 79 80 m_hostname = hostname; 81 82 // Set the default audio format 83 SetSoundFormat(pcm_default); 84 85 // Initialize some variable 86 m_snderror = wxSOUND_NOERROR; 87 m_esd_stop = true; 88 m_q_filled = true; 89 m_esd_ok = true; 90 m_fd_output= -1; 91 m_fd_input = -1; 92#endif // defined HAVE_ESD_H 93} 94 95wxSoundStreamESD::~wxSoundStreamESD() 96{ 97#ifdef HAVE_ESD_H 98 if (!m_esd_stop) 99 StopProduction(); 100#endif // defined HAVE_ESD_H 101} 102 103// -------------------------------------------------------------------------- 104// Read several samples 105// -------------------------------------------------------------------------- 106 107wxSoundStream& wxSoundStreamESD::Read(void *buffer, wxUint32 len) 108{ 109#ifndef HAVE_ESD_H 110 m_snderror = wxSOUND_INVDEV; 111 return *this; 112#else 113 int ret; 114 115 if (m_esd_stop) { 116 m_snderror = wxSOUND_NOTSTARTED; 117 return *this; 118 } 119 120 ret = read(m_fd_input, buffer, len); 121 m_lastcount = (wxUint32)ret; 122 123 if (ret < 0) 124 m_snderror = wxSOUND_IOERROR; 125 else 126 m_snderror = wxSOUND_NOERROR; 127 128 return *this; 129#endif // defined HAVE_ESD_H 130} 131 132// -------------------------------------------------------------------------- 133// Write several samples 134// -------------------------------------------------------------------------- 135wxSoundStream& wxSoundStreamESD::Write(const void *buffer, wxUint32 len) 136{ 137#ifndef HAVE_ESD_H 138 m_snderror = wxSOUND_INVDEV; 139 return *this; 140#else 141 int ret; 142 143 if (m_esd_stop) { 144 m_lastcount = 0; 145 m_snderror = wxSOUND_NOTSTARTED; 146 return *this; 147 } 148 149 ret = write(m_fd_output, buffer, len); 150 m_lastcount = (wxUint32)ret; 151 152 if (ret < 0) 153 m_snderror = wxSOUND_IOERROR; 154 else 155 m_snderror = wxSOUND_NOERROR; 156 157 m_q_filled = true; 158 159 return *this; 160#endif // defined HAVE_ESD_H 161} 162 163// -------------------------------------------------------------------------- 164// SetSoundFormat(): this function specifies which format we want and which 165// format is available 166// -------------------------------------------------------------------------- 167bool wxSoundStreamESD::SetSoundFormat(const wxSoundFormatBase& format) 168{ 169#ifndef HAVE_ESD_H 170 m_snderror = wxSOUND_INVDEV; 171 return false; 172#else 173 wxSoundFormatPcm *pcm_format; 174 175 if (format.GetType() != wxSOUND_PCM) { 176 m_snderror = wxSOUND_INVFRMT; 177 return false; 178 } 179 180 if (!m_esd_ok) { 181 m_snderror = wxSOUND_INVDEV; 182 return false; 183 } 184 185 if (m_sndformat) 186 delete m_sndformat; 187 188 m_sndformat = format.Clone(); 189 if (!m_sndformat) { 190 m_snderror = wxSOUND_MEMERROR; 191 return false; 192 } 193 pcm_format = (wxSoundFormatPcm *)m_sndformat; 194 195 // Detect the best format 196 DetectBest(pcm_format); 197 198 m_snderror = wxSOUND_NOERROR; 199 if (*pcm_format != format) { 200 m_snderror = wxSOUND_NOEXACT; 201 return false; 202 } 203 return true; 204#endif // defined HAVE_ESD_H 205} 206 207// -------------------------------------------------------------------------- 208// _wxSound_OSS_CBack (internal): it is called when the driver (ESD) is 209// ready for a next buffer. 210// -------------------------------------------------------------------------- 211#if defined(__WXGTK__) && defined(HAVE_ESD_H) 212static void _wxSound_OSS_CBack(gpointer data, int source, 213 GdkInputCondition condition) 214{ 215 wxSoundStreamESD *esd = (wxSoundStreamESD *)data; 216 217 switch (condition) { 218 case GDK_INPUT_READ: 219 esd->WakeUpEvt(wxSOUND_INPUT); 220 break; 221 case GDK_INPUT_WRITE: 222 esd->WakeUpEvt(wxSOUND_OUTPUT); 223 break; 224 default: 225 break; 226 } 227} 228#endif 229 230 231// -------------------------------------------------------------------------- 232// WakeUpEvt() (internal): it is called by _wxSound_OSS_CBack to bypass the 233// C++ protection 234// -------------------------------------------------------------------------- 235void wxSoundStreamESD::WakeUpEvt(int evt) 236{ 237 m_q_filled = false; 238 OnSoundEvent(evt); 239} 240 241// -------------------------------------------------------------------------- 242// StartProduction(): see wxSoundStream 243// -------------------------------------------------------------------------- 244bool wxSoundStreamESD::StartProduction(int evt) 245{ 246#ifndef HAVE_ESD_H 247 m_snderror = wxSOUND_INVDEV; 248 return false; 249#else 250 wxSoundFormatPcm *pcm; 251 int flag = 0; 252 253 if (!m_esd_ok) { 254 m_snderror = wxSOUND_INVDEV; 255 return false; 256 } 257 258 if (!m_esd_stop) 259 StopProduction(); 260 261 pcm = (wxSoundFormatPcm *)m_sndformat; 262 263 flag |= (pcm->GetBPS() == 16) ? ESD_BITS16 : ESD_BITS8; 264 flag |= (pcm->GetChannels() == 2) ? ESD_STEREO : ESD_MONO; 265 266 if ((evt & wxSOUND_OUTPUT) != 0) { 267 flag |= ESD_PLAY | ESD_STREAM; 268 m_fd_output = esd_play_stream(flag, pcm->GetSampleRate(), NULL, 269 MY_ESD_NAME); 270 } 271 272 if ((evt & wxSOUND_INPUT) != 0) { 273 flag |= ESD_RECORD | ESD_STREAM; 274 m_fd_input = esd_record_stream(flag, pcm->GetSampleRate(), NULL, 275 MY_ESD_NAME); 276 } 277 278#ifdef __WXGTK__ 279 if ((evt & wxSOUND_OUTPUT) != 0) { 280 m_tag_output = gdk_input_add(m_fd_output, GDK_INPUT_WRITE, 281 _wxSound_OSS_CBack, (gpointer)this); 282 } 283 if ((evt & wxSOUND_INPUT) != 0) { 284 m_tag_input = gdk_input_add(m_fd_input, GDK_INPUT_READ, 285 _wxSound_OSS_CBack, (gpointer)this); 286 } 287#endif 288 289 m_esd_stop = false; 290 m_q_filled = false; 291 292 return true; 293#endif // defined HAVE_ESD_H 294} 295 296// -------------------------------------------------------------------------- 297// StopProduction(): see wxSoundStream 298// -------------------------------------------------------------------------- 299bool wxSoundStreamESD::StopProduction() 300{ 301#ifndef HAVE_ESD_H 302 m_snderror = wxSOUND_INVDEV; 303 return false; 304#else 305 if (m_esd_stop) 306 return false; 307 308 if (m_fd_input != -1) { 309 esd_close(m_fd_input); 310#ifdef __WXGTK__ 311 gdk_input_remove(m_tag_input); 312#endif 313 } 314 if (m_fd_output != -1) { 315 esd_close(m_fd_output); 316#ifdef __WXGTK__ 317 gdk_input_remove(m_tag_output); 318#endif 319 } 320 321 m_fd_input = -1; 322 m_fd_output= -1; 323 m_esd_stop = true; 324 m_q_filled = true; 325 return true; 326#endif // defined HAVE_ESD_H 327} 328 329// 330// Detect the closest format (The best). 331// 332void wxSoundStreamESD::DetectBest(wxSoundFormatPcm *pcm) 333{ 334#ifndef HAVE_ESD_H 335 m_snderror = wxSOUND_INVDEV; 336 return; 337#else 338 wxSoundFormatPcm best_pcm; 339 340 // We change neither the number of channels nor the sample rate 341 // because ESD is clever. 342 343 best_pcm.SetSampleRate(pcm->GetSampleRate()); 344 best_pcm.SetChannels(pcm->GetChannels()); 345 346 // It supports 16 bits 347 if (pcm->GetBPS() >= 16) 348 best_pcm.SetBPS(16); 349 else 350 best_pcm.SetBPS(8); 351 352 best_pcm.SetOrder(wxLITTLE_ENDIAN); 353 best_pcm.Signed(true); 354 355 // Finally recopy the new format 356 *pcm = best_pcm; 357#endif // defined HAVE_ESD_H 358} 359 360