Uncommented beaudio code
[pwlib.git] / src / ptlib / unix / macosaudio.cxx
blob534ead317bfd8fdf57395df59a85051a965d9e5d
1 /*
2 * macosxaudio.cxx
4 * Sound driver implementation.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s):
29 * $Log$
30 * Revision 1.3 2002/02/09 00:52:01 robertj
31 * Slight adjustment to API and documentation for volume functions.
33 * Revision 1.2 2002/02/07 20:57:21 dereks
34 * add SetVolume and GetVolume methods to PSoundChannel
36 * Revision 1.1 2001/08/11 15:38:43 rogerh
37 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
42 #pragma implementation "sound.h"
44 #include <ptlib.h>
46 // goddamn apple headers
47 #undef TCP_NODELAY
48 #undef TCP_MAXSEG
50 //#include "macosaudio/SoundInput.h"
51 //#include "macosaudio/SoundPlayer.h"
52 #include "macosaudio/MacMain.h" // interface to the Main Thread for Carbon
53 #include "macosaudio/ringbuffer.h"
55 #define DEFAULTSAMPLESIZE 16
57 // PSound
58 PSound::PSound(unsigned channels,
59 unsigned samplesPerSecond,
60 unsigned bitsPerSample,
61 PINDEX bufferSize,
62 const BYTE * buffer)
64 // Copy format
65 SetFormat(channels, samplesPerSecond, DEFAULTSAMPLESIZE);
67 // Copy data passed
68 SetSize(bufferSize);
69 if( buffer )
70 memcpy(GetPointer(), buffer, bufferSize);
74 PSound::PSound(const PFilePath & filename)
76 // Copy format
77 SetFormat(1, 8000, DEFAULTSAMPLESIZE);
79 // Load the sound
80 SetSize(0);
81 Load(filename);
85 PSound & PSound::operator=(const PBYTEArray & data)
87 PBYTEArray::operator=(data);
88 return *this;
92 void PSound::SetFormat(unsigned channels,
93 unsigned samplesPerSecond,
94 unsigned bitsPerSample)
96 formatInfo.SetSize( 0 ); // media format inside
98 // Build our format definition
99 sampleSize = bitsPerSample;
100 sampleRate = samplesPerSecond;
101 numChannels = channels;
104 BOOL PSound::Load(const PFilePath & filename)
106 return FALSE;
110 BOOL PSound::Save(const PFilePath & filename)
112 return FALSE;
116 PSoundChannel::PSoundChannel() :
117 mpInput(NULL),
118 mNumChannels(1), mSampleRate(8000), mBitsPerSample(16)
120 Construct();
124 PSoundChannel::PSoundChannel(const PString & device,
125 Directions dir,
126 unsigned numChannels,
127 unsigned sampleRate,
128 unsigned bitsPerSample) :
129 mpInput(NULL),
130 mNumChannels(numChannels), mSampleRate(sampleRate), mBitsPerSample(bitsPerSample)
132 Construct();
134 Open(device, dir, numChannels, sampleRate, bitsPerSample);
138 void PSoundChannel::Construct()
143 PSoundChannel::~PSoundChannel()
145 Close();
147 if( direction == Recorder && mpInput )
148 delete mpInput;
152 PStringArray PSoundChannel::GetDeviceNames(Directions /*dir*/)
154 PStringArray array;
156 array[0]= "built-in audio";
157 return array;
161 PString PSoundChannel::GetDefaultDevice(Directions /*dir*/)
163 return "built-in audio";
167 BOOL PSoundChannel::Open(const PString & dev,
168 Directions dir,
169 unsigned numChannels,
170 unsigned sampleRate,
171 unsigned bitsPerSample)
173 Close();
174 PTRACE(1, "PSoundChannel::Open: " << dev << "," << (int)dir);
176 device = dev;
177 direction = dir;
179 SetFormat(numChannels, sampleRate, bitsPerSample);
181 soundParams sp(numChannels, bitsPerSample, sampleRate);
183 if( direction == Player )
185 int err;
187 // XXX PString only has a const unsigned char * operator
188 // XXX if HAS_UNICODE is not defined -- yet they don't provide
189 // XXX any decent operators for portably extracting into a
190 // XXX char buffer.
191 commandRequest r(kOpenPlayer,
192 (const unsigned char *)device, &sp);
193 err = r.CarbonQueue();
194 if (err == 0 && r.m_status == 0) {
195 os_handle = r.m_result;
197 else {
198 fprintf(stderr,"OpenPlayer failed! %d\n",err);
199 goto bail;
202 r = commandRequest(kSetFormatPlayer, os_handle, &sp);
203 err = r.CarbonQueue();
204 if (err != 0 || r.m_status)
205 goto bail; // destructor will close channel
207 PTRACE(1, "PSoundChannel::Open(p): returning TRUE");
208 return TRUE;
210 else
211 if( direction == Recorder )
213 mpInput = new JRingBuffer(4096);
214 if (!mpInput) goto bail;
216 int err;
217 commandRequest r(kOpenRecorder, (const unsigned char *)dev, &sp);
218 err = r.CarbonQueue();
219 if (err == 0 && r.m_status == 0) {
220 os_handle = r.m_result;
222 else goto bail;
223 r = commandRequest(kSetFormatRecorder, os_handle, &sp);
224 err = r.CarbonQueue();
225 if (err || r.m_status) goto bail;
227 r = commandRequest(kStartRecorder,
228 os_handle, (void *)mpInput);
229 err = r.CarbonQueue();
230 if (err || r.m_status) goto bail;
232 PTRACE(1, "PSoundChannel::Open(r): returning TRUE");
233 return TRUE;
234 } else assert(0); // bad direction type
236 bail: // badness
237 return FALSE;
241 BOOL PSoundChannel::SetFormat(unsigned numChannels,
242 unsigned sampleRate,
243 unsigned bitsPerSample)
245 PTRACE(1, "PSoundChannel::SetFormat: " << numChannels << "," << sampleRate << "," << bitsPerSample);
247 PAssert(numChannels >= 1 && numChannels <= 2, PInvalidParameter);
248 PAssert( bitsPerSample == 0 ||
249 bitsPerSample == 8 ||
250 bitsPerSample == 16 ||
251 bitsPerSample == 32, PInvalidParameter);
253 if( !bitsPerSample )
254 PError << "\tWarning: sample bits parameter is zero. Float?" << endl;
256 mNumChannels = numChannels;
257 mSampleRate = sampleRate;
258 mBitsPerSample = bitsPerSample;
260 soundParams sp(numChannels, bitsPerSample, sampleRate);
262 if( direction == Player )
264 if( os_handle < 0 )
265 return FALSE;
267 commandRequest r(kSetFormatPlayer, os_handle, &sp);
268 int err = r.CarbonQueue();
269 if (err || r.m_status)
270 return FALSE;
271 return TRUE;
273 else
274 if( direction == Recorder )
276 if( os_handle < 0 )
277 return FALSE;
279 commandRequest r(kSetFormatRecorder, os_handle, &sp);
280 int err = r.CarbonQueue();
281 if (err || r.m_status)
282 return FALSE;
283 return TRUE;
286 return FALSE;
289 BOOL PSoundChannel::Read( void * buf, PINDEX len)
291 if( direction == Player )
293 return FALSE;
295 else
296 if( direction == Recorder )
298 static int total_read = 0;
299 static int message_level = 0;
301 if( !mpInput )
302 return FALSE;
304 int rlen = mpInput->Read(buf, len);
305 PAssert(rlen == -1 || rlen == len, "huh?");
306 if (rlen >= 0) {
307 static Nanoseconds gStartTime, gMostRecentTime;
308 if (total_read == 0) gStartTime = AbsoluteToNanoseconds(UpTime());
309 else gMostRecentTime = AbsoluteToNanoseconds(UpTime());
310 total_read += rlen;
311 if (total_read >= 80000 && message_level == 0) {
312 fprintf(stderr,"80000 bytes read\n");
313 message_level = 1;
315 else if (total_read >= 240000 && message_level == 1) {
316 fprintf(stderr,"240000 bytes read at %d samples per sec\n",
317 (total_read*10) /
318 (long)( (*(long long *)&gMostRecentTime -
319 *(long long *)&gStartTime ) / 100000000LL));
320 message_level = 2;
324 return rlen == len? TRUE : FALSE;
327 return FALSE;
330 BOOL PSoundChannel::Write( const void * buf, PINDEX len)
332 if( direction == Player )
334 commandRequest r(kPlaySample, (unsigned long)os_handle,
335 (const unsigned char *)buf,
336 (unsigned long)len);
337 int err = r.CarbonQueue();
338 if (err || r.m_status) {
339 fprintf(stderr,"Write failed: err %d status %d\n", err, r.m_status);
340 return FALSE;
343 return TRUE;
345 else
346 if( direction == Recorder )
348 return FALSE;
351 return FALSE;
354 BOOL PSoundChannel::Close()
356 if( direction == Player )
358 if (os_handle >= 0) {
359 commandRequest r(kClosePlayer, os_handle);
360 (void) r.CarbonQueue();
362 isInitialised = false;
363 os_handle = -1;
364 return TRUE;
366 else
367 if( direction == Recorder )
369 if (os_handle > 0) {
370 commandRequest r(kCloseRecorder, os_handle);
371 (void) r.CarbonQueue();
374 isInitialised = false;
375 os_handle = -1;
376 return TRUE;
379 return FALSE;
382 BOOL PSoundChannel::SetBuffers(PINDEX size, PINDEX count)
384 PAssert(size > 0 && count > 0 && count < 65536, PInvalidParameter);
386 return TRUE;
390 BOOL PSoundChannel::GetBuffers(PINDEX & size, PINDEX & count)
392 return TRUE;
396 BOOL PSoundChannel::PlaySound(const PSound & sound, BOOL wait)
398 if (!Write((const BYTE *)sound, sound.GetSize()))
399 return FALSE;
401 if (wait)
402 return WaitForPlayCompletion();
403 return TRUE;
407 BOOL PSoundChannel::PlayFile(const PFilePath & filename, BOOL wait)
409 return FALSE;
413 BOOL PSoundChannel::HasPlayCompleted()
415 commandRequest r(kIsPlaying, os_handle);
416 (void)r.CarbonQueue();
417 return r.m_result ? FALSE : TRUE;
421 BOOL PSoundChannel::WaitForPlayCompletion()
423 commandRequest r(kWaitForPlayCompletion, os_handle);
424 int err = r.CarbonQueue();
425 if (err == 0) err = r.m_status;
426 return err == 0;
430 BOOL PSoundChannel::RecordSound(PSound & sound)
432 return FALSE;
436 BOOL PSoundChannel::RecordFile(const PFilePath & filename)
438 return FALSE;
442 BOOL PSoundChannel::StartRecording()
444 if( direction == Player )
446 return FALSE;
448 else
449 if( direction == Recorder )
451 PAssertNULL(mpInput);
453 commandRequest r(kStartRecorder, os_handle, mpInput);
454 int err = r.CarbonQueue();
455 if (err == 0) err = r.m_status;
457 if( err == 0 )
458 PError << "Recording started" << endl;
459 return err == 0 ? TRUE : FALSE;
462 return FALSE;
466 // Is there any record data to read?
467 BOOL PSoundChannel::IsRecordBufferFull()
469 if( direction == Recorder )
471 PAssertNULL(mpInput);
472 return !mpInput->IsEmpty();
474 return FALSE;
478 BOOL PSoundChannel::AreAllRecordBuffersFull()
480 if( direction == Recorder )
482 PAssertNULL(mpInput);
483 return mpInput->IsFull();
485 return FALSE;
489 BOOL PSoundChannel::WaitForRecordBufferFull()
491 if( direction == Recorder )
493 PAssertNULL(mpInput);
494 return mpInput->WaitForData();
496 return FALSE;
500 BOOL PSoundChannel::WaitForAllRecordBuffersFull()
502 return FALSE;
506 BOOL PSoundChannel::Abort()
508 if( direction == Player )
510 commandRequest r(kStopPlayer, os_handle);
511 int err = r.CarbonQueue();
512 if (err == 0) err = r.m_status;
513 return err == 0;
515 else
516 if( direction == Recorder )
518 if(!mpInput)
519 return FALSE;
521 commandRequest r(kStopRecorder, os_handle);
522 int err = r.CarbonQueue();
523 if (err == 0) err = r.m_status;
524 return TRUE;
527 return FALSE;
530 BOOL PSoundChannel::SetVolume(unsigned newVolume)
532 cerr << __FILE__ << "PSoundChannel :: SetVolume called in error. Please fix"<<endl;
533 return FALSE;
536 BOOL PSoundChannel::GetVolume(unsigned & volume)
538 cerr << __FILE__ << "PSoundChannel :: GetVolume called in error. Please fix"<<endl;
539 return FALSE;
543 // End of file