aboutsummaryrefslogtreecommitdiff
path: root/pd/portaudio_v18/pa_beos
diff options
context:
space:
mode:
Diffstat (limited to 'pd/portaudio_v18/pa_beos')
-rw-r--r--pd/portaudio_v18/pa_beos/PlaybackNode.cc538
-rw-r--r--pd/portaudio_v18/pa_beos/PlaybackNode.h108
-rw-r--r--pd/portaudio_v18/pa_beos/pa_beos_mk.cc441
3 files changed, 0 insertions, 1087 deletions
diff --git a/pd/portaudio_v18/pa_beos/PlaybackNode.cc b/pd/portaudio_v18/pa_beos/PlaybackNode.cc
deleted file mode 100644
index a93b8412..00000000
--- a/pd/portaudio_v18/pa_beos/PlaybackNode.cc
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * $Id: PlaybackNode.cc,v 1.1.1.1 2002/01/22 00:52:07 phil Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * BeOS Media Kit Implementation by Joshua Haberman
- *
- * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * ---
- *
- * Significant portions of this file are based on sample code from Be. The
- * Be Sample Code Licence follows:
- *
- * Copyright 1991-1999, Be Incorporated.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions, and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-
-#include <be/media/BufferGroup.h>
-#include <be/media/Buffer.h>
-#include <be/media/TimeSource.h>
-
-#include "PlaybackNode.h"
-
-#define PRINT(x) { printf x; fflush(stdout); }
-
-#ifdef DEBUG
-#define DBUG(x) PRINT(x)
-#else
-#define DBUG(x)
-#endif
-
-
-PaPlaybackNode::PaPlaybackNode(uint32 channels, float frame_rate, uint32 frames_per_buffer,
- PortAudioCallback* callback, void *user_data) :
- BMediaNode("PortAudio input node"),
- BBufferProducer(B_MEDIA_RAW_AUDIO),
- BMediaEventLooper(),
- mAborted(false),
- mRunning(false),
- mBufferGroup(NULL),
- mDownstreamLatency(0),
- mStartTime(0),
- mCallback(callback),
- mUserData(user_data),
- mFramesPerBuffer(frames_per_buffer)
-{
- DBUG(("Constructor called.\n"));
-
- mPreferredFormat.type = B_MEDIA_RAW_AUDIO;
- mPreferredFormat.u.raw_audio.channel_count = channels;
- mPreferredFormat.u.raw_audio.frame_rate = frame_rate;
- mPreferredFormat.u.raw_audio.byte_order =
- (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
- mPreferredFormat.u.raw_audio.buffer_size =
- media_raw_audio_format::wildcard.buffer_size;
-
- mOutput.destination = media_destination::null;
- mOutput.format = mPreferredFormat;
-
- /* The amount of time it takes for this node to produce a buffer when
- * asked. Essentially, it is how long the user's callback takes to run.
- * We set this to be the length of the sound data each buffer of the
- * requested size can hold. */
- //mInternalLatency = (bigtime_t)(1000000 * frames_per_buffer / frame_rate);
-
- /* ACK! it seems that the mixer (at least on my machine) demands that IT
- * specify the buffer size, so for now I'll just make a generic guess here */
- mInternalLatency = 1000000 / 20;
-}
-
-
-
-PaPlaybackNode::~PaPlaybackNode()
-{
- DBUG(("Destructor called.\n"));
- Quit(); /* Stop the BMediaEventLooper thread */
-}
-
-
-/*************************
- *
- * Local methods
- *
- */
-
-bool PaPlaybackNode::IsRunning()
-{
- return mRunning;
-}
-
-
-PaTimestamp PaPlaybackNode::GetStreamTime()
-{
- BTimeSource *timeSource = TimeSource();
- PaTimestamp time = (timeSource->Now() - mStartTime) *
- mPreferredFormat.u.raw_audio.frame_rate / 1000000;
- return time;
-}
-
-
-void PaPlaybackNode::SetSampleFormat(PaSampleFormat inFormat,
- PaSampleFormat outFormat)
-{
- uint32 beOutFormat;
-
- switch(outFormat)
- {
- case paFloat32:
- beOutFormat = media_raw_audio_format::B_AUDIO_FLOAT;
- mOutputSampleWidth = 4;
- break;
-
- case paInt16:
- beOutFormat = media_raw_audio_format::B_AUDIO_SHORT;
- mOutputSampleWidth = 2;
- break;
-
- case paInt32:
- beOutFormat = media_raw_audio_format::B_AUDIO_INT;
- mOutputSampleWidth = 4;
- break;
-
- case paInt8:
- beOutFormat = media_raw_audio_format::B_AUDIO_CHAR;
- mOutputSampleWidth = 1;
- break;
-
- case paUInt8:
- beOutFormat = media_raw_audio_format::B_AUDIO_UCHAR;
- mOutputSampleWidth = 1;
- break;
-
- case paInt24:
- case paPackedInt24:
- case paCustomFormat:
- DBUG(("Unsupported output format: %x\n", outFormat));
- break;
-
- default:
- DBUG(("Unknown output format: %x\n", outFormat));
- }
-
- mPreferredFormat.u.raw_audio.format = beOutFormat;
- mFramesPerBuffer * mPreferredFormat.u.raw_audio.channel_count * mOutputSampleWidth;
-}
-
-BBuffer *PaPlaybackNode::FillNextBuffer(bigtime_t time)
-{
- /* Get a buffer from the buffer group */
- BBuffer *buf = mBufferGroup->RequestBuffer(
- mOutput.format.u.raw_audio.buffer_size, BufferDuration());
- unsigned long frames = mOutput.format.u.raw_audio.buffer_size /
- mOutputSampleWidth / mOutput.format.u.raw_audio.channel_count;
- bigtime_t start_time;
- int ret;
-
- if( !buf )
- {
- DBUG(("Unable to allocate a buffer\n"));
- return NULL;
- }
-
- start_time = mStartTime +
- (bigtime_t)((double)mSamplesSent /
- (double)mOutput.format.u.raw_audio.frame_rate /
- (double)mOutput.format.u.raw_audio.channel_count *
- 1000000.0);
-
- /* Now call the user callback to get the data */
- ret = mCallback(NULL, /* Input buffer */
- buf->Data(), /* Output buffer */
- frames, /* Frames per buffer */
- mSamplesSent / mOutput.format.u.raw_audio.channel_count, /* timestamp */
- mUserData);
-
- if( ret )
- mAborted = true;
-
- media_header *hdr = buf->Header();
-
- hdr->type = B_MEDIA_RAW_AUDIO;
- hdr->size_used = mOutput.format.u.raw_audio.buffer_size;
- hdr->time_source = TimeSource()->ID();
- hdr->start_time = start_time;
-
- return buf;
-}
-
-
-
-
-/*************************
- *
- * BMediaNode methods
- *
- */
-
-BMediaAddOn *PaPlaybackNode::AddOn( int32 * ) const
-{
- DBUG(("AddOn() called.\n"));
- return NULL; /* we don't provide service to outside applications */
-}
-
-
-status_t PaPlaybackNode::HandleMessage( int32 message, const void *data,
- size_t size )
-{
- DBUG(("HandleMessage() called.\n"));
- return B_ERROR; /* we don't define any custom messages */
-}
-
-
-
-
-/*************************
- *
- * BMediaEventLooper methods
- *
- */
-
-void PaPlaybackNode::NodeRegistered()
-{
- DBUG(("NodeRegistered() called.\n"));
-
- /* Start the BMediaEventLooper thread */
- SetPriority(B_REAL_TIME_PRIORITY);
- Run();
-
- /* set up as much information about our output as we can */
- mOutput.source.port = ControlPort();
- mOutput.source.id = 0;
- mOutput.node = Node();
- ::strcpy(mOutput.name, "PortAudio Playback");
-}
-
-
-void PaPlaybackNode::HandleEvent( const media_timed_event *event,
- bigtime_t lateness, bool realTimeEvent )
-{
- // DBUG(("HandleEvent() called.\n"));
- status_t err;
-
- switch(event->type)
- {
- case BTimedEventQueue::B_START:
- DBUG((" Handling a B_START event\n"));
- if( RunState() != B_STARTED )
- {
- mStartTime = event->event_time + EventLatency();
- mSamplesSent = 0;
- mAborted = false;
- mRunning = true;
- media_timed_event firstEvent( mStartTime,
- BTimedEventQueue::B_HANDLE_BUFFER );
- EventQueue()->AddEvent( firstEvent );
- }
- break;
-
- case BTimedEventQueue::B_STOP:
- DBUG((" Handling a B_STOP event\n"));
- mRunning = false;
- EventQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true,
- BTimedEventQueue::B_HANDLE_BUFFER );
- break;
-
- case BTimedEventQueue::B_HANDLE_BUFFER:
- //DBUG((" Handling a B_HANDLE_BUFFER event\n"));
-
- /* make sure we're started and connected */
- if( RunState() != BMediaEventLooper::B_STARTED ||
- mOutput.destination == media_destination::null )
- break;
-
- BBuffer *buffer = FillNextBuffer(event->event_time);
-
- /* make sure we weren't aborted while this routine was running.
- * this can happen in one of two ways: either the callback returned
- * nonzero (in which case mAborted is set in FillNextBuffer() ) or
- * the client called AbortStream */
- if( mAborted )
- {
- if( buffer )
- buffer->Recycle();
- Stop(0, true);
- break;
- }
-
- if( buffer )
- {
- err = SendBuffer(buffer, mOutput.destination);
- if( err != B_OK )
- buffer->Recycle();
- }
-
- mSamplesSent += mOutput.format.u.raw_audio.buffer_size / mOutputSampleWidth;
-
- /* Now schedule the next buffer event, so we can send another
- * buffer when this one runs out. We calculate when it should
- * happen by calculating when the data we just sent will finish
- * playing.
- *
- * NOTE, however, that the event will actually get generated
- * earlier than we specify, to account for the latency it will
- * take to produce the buffer. It uses the latency value we
- * specified in SetEventLatency() to determine just how early
- * to generate it. */
-
- /* totalPerformanceTime includes the time represented by the buffer
- * we just sent */
- bigtime_t totalPerformanceTime = (bigtime_t)((double)mSamplesSent /
- (double)mOutput.format.u.raw_audio.channel_count /
- (double)mOutput.format.u.raw_audio.frame_rate * 1000000.0);
-
- bigtime_t nextEventTime = mStartTime + totalPerformanceTime;
-
- media_timed_event nextBufferEvent(nextEventTime,
- BTimedEventQueue::B_HANDLE_BUFFER);
- EventQueue()->AddEvent(nextBufferEvent);
-
- break;
-
- }
-}
-
-
-
-
-/*************************
- *
- * BBufferProducer methods
- *
- */
-
-status_t PaPlaybackNode::FormatSuggestionRequested( media_type type,
- int32 /*quality*/, media_format* format )
-{
- /* the caller wants to know this node's preferred format and provides
- * a suggestion, asking if we support it */
- DBUG(("FormatSuggestionRequested() called.\n"));
-
- if(!format)
- return B_BAD_VALUE;
-
- *format = mPreferredFormat;
-
- /* we only support raw audio (a wildcard is okay too) */
- if ( type == B_MEDIA_UNKNOWN_TYPE || type == B_MEDIA_RAW_AUDIO )
- return B_OK;
- else
- return B_MEDIA_BAD_FORMAT;
-}
-
-
-status_t PaPlaybackNode::FormatProposal( const media_source& output,
- media_format* format )
-{
- /* This is similar to FormatSuggestionRequested(), but it is actually part
- * of the negotiation process. We're given the opportunity to specify any
- * properties that are wildcards (ie. properties that the other node doesn't
- * care one way or another about) */
- DBUG(("FormatProposal() called.\n"));
-
- /* Make sure this proposal really applies to our output */
- if( output != mOutput.source )
- return B_MEDIA_BAD_SOURCE;
-
- /* We return two things: whether we support the proposed format, and our own
- * preferred format */
- *format = mPreferredFormat;
-
- if( format->type == B_MEDIA_UNKNOWN_TYPE || format->type == B_MEDIA_RAW_AUDIO )
- return B_OK;
- else
- return B_MEDIA_BAD_FORMAT;
-}
-
-
-status_t PaPlaybackNode::FormatChangeRequested( const media_source& source,
- const media_destination& destination, media_format* io_format, int32* )
-{
- /* we refuse to change formats, supporting only 1 */
- DBUG(("FormatChangeRequested() called.\n"));
-
- return B_ERROR;
-}
-
-
-status_t PaPlaybackNode::GetNextOutput( int32* cookie, media_output* out_output )
-{
- /* this is where we allow other to enumerate our outputs -- the cookie is
- * an integer we can use to keep track of where we are in enumeration. */
- DBUG(("GetNextOutput() called.\n"));
-
- if( *cookie == 0 )
- {
- *out_output = mOutput;
- *cookie = 1;
- return B_OK;
- }
-
- return B_BAD_INDEX;
-}
-
-
-status_t PaPlaybackNode::DisposeOutputCookie( int32 cookie )
-{
- DBUG(("DisposeOutputCookie() called.\n"));
- return B_OK;
-}
-
-
-void PaPlaybackNode::LateNoticeReceived( const media_source& what,
- bigtime_t how_much, bigtime_t performance_time )
-{
- /* This function is called as notification that a buffer we sent wasn't
- * received by the time we stamped it with -- it got there late. Basically,
- * it means we underestimated our own latency, so we should increase it */
- DBUG(("LateNoticeReceived() called.\n"));
-
- if( what != mOutput.source )
- return;
-
- if( RunMode() == B_INCREASE_LATENCY )
- {
- mInternalLatency += how_much;
- SetEventLatency( mDownstreamLatency + mInternalLatency );
- DBUG(("Increasing latency to %Ld\n", mDownstreamLatency + mInternalLatency));
- }
- else
- DBUG(("I don't know what to do with this notice!"));
-}
-
-
-void PaPlaybackNode::EnableOutput( const media_source& what, bool enabled,
- int32* )
-{
- DBUG(("EnableOutput() called.\n"));
- /* stub -- we don't support this yet */
-}
-
-
-status_t PaPlaybackNode::PrepareToConnect( const media_source& what,
- const media_destination& where, media_format* format,
- media_source* out_source, char* out_name )
-{
- /* the final stage of format negotiations. here we _must_ make specific any
- * remaining wildcards */
- DBUG(("PrepareToConnect() called.\n"));
-
- /* make sure this really refers to our source */
- if( what != mOutput.source )
- return B_MEDIA_BAD_SOURCE;
-
- /* make sure we're not already connected */
- if( mOutput.destination != media_destination::null )
- return B_MEDIA_ALREADY_CONNECTED;
-
- if( format->type != B_MEDIA_RAW_AUDIO )
- return B_MEDIA_BAD_FORMAT;
-
- if( format->u.raw_audio.format != mPreferredFormat.u.raw_audio.format )
- return B_MEDIA_BAD_FORMAT;
-
- if( format->u.raw_audio.buffer_size ==
- media_raw_audio_format::wildcard.buffer_size )
- {
- DBUG(("We were left to decide buffer size: choosing 2048"));
- format->u.raw_audio.buffer_size = 2048;
- }
- else
- DBUG(("Using consumer specified buffer size of %lu.\n",
- format->u.raw_audio.buffer_size));
-
- /* Reserve the connection, return the information */
- mOutput.destination = where;
- mOutput.format = *format;
- *out_source = mOutput.source;
- strncpy( out_name, mOutput.name, B_MEDIA_NAME_LENGTH );
-
- return B_OK;
-}
-
-
-void PaPlaybackNode::Connect(status_t error, const media_source& source,
- const media_destination& destination, const media_format& format, char* io_name)
-{
- DBUG(("Connect() called.\n"));
-
diff --git a/pd/portaudio_v18/pa_beos/PlaybackNode.h b/pd/portaudio_v18/pa_beos/PlaybackNode.h
deleted file mode 100644
index c9582056..00000000
--- a/pd/portaudio_v18/pa_beos/PlaybackNode.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * $Id: PlaybackNode.h,v 1.1.1.1 2002/01/22 00:52:08 phil Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * BeOS Media Kit Implementation by Joshua Haberman
- *
- * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <be/media/MediaRoster.h>
-#include <be/media/MediaEventLooper.h>
-#include <be/media/BufferProducer.h>
-
-#include "portaudio.h"
-
-class PaPlaybackNode :
- public BBufferProducer,
- public BMediaEventLooper
-{
-
-public:
- PaPlaybackNode( uint32 channels, float frame_rate, uint32 frames_per_buffer,
- PortAudioCallback *callback, void *user_data );
- ~PaPlaybackNode();
-
-
- /* Local methods ******************************************/
-
- BBuffer *FillNextBuffer(bigtime_t time);
- void SetSampleFormat(PaSampleFormat inFormat, PaSampleFormat outFormat);
- bool IsRunning();
- PaTimestamp GetStreamTime();
-
- /* BMediaNode methods *************************************/
-
- BMediaAddOn* AddOn( int32 * ) const;
- status_t HandleMessage( int32 message, const void *data, size_t size );
-
- /* BMediaEventLooper methods ******************************/
-
- void HandleEvent( const media_timed_event *event, bigtime_t lateness,
- bool realTimeEvent );
- void NodeRegistered();
-
- /* BBufferProducer methods ********************************/
-
- status_t FormatSuggestionRequested( media_type type, int32 quality,
- media_format* format );
- status_t FormatProposal( const media_source& output, media_format* format );
- status_t FormatChangeRequested( const media_source& source,
- const media_destination& destination, media_format* io_format, int32* );
-
- status_t GetNextOutput( int32* cookie, media_output* out_output );
- status_t DisposeOutputCookie( int32 cookie );
-
- void LateNoticeReceived( const media_source& what, bigtime_t how_much,
- bigtime_t performance_time );
- void EnableOutput( const media_source& what, bool enabled, int32* _deprecated_ );
-
- status_t PrepareToConnect( const media_source& what,
- const media_destination& where, media_format* format,
- media_source* out_source, char* out_name );
- void Connect(status_t error, const media_source& source,
- const media_destination& destination, const media_format& format,
- char* io_name);
- void Disconnect(const media_source& what, const media_destination& where);
-
- status_t SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup);
-
- bool mAborted;
-
-private:
- media_output mOutput;
- media_format mPreferredFormat;
- uint32 mOutputSampleWidth, mFramesPerBuffer;
- BBufferGroup *mBufferGroup;
- bigtime_t mDownstreamLatency, mInternalLatency, mStartTime;
- uint64 mSamplesSent;
- PortAudioCallback *mCallback;
- void *mUserData;
- bool mRunning;
-
-};
-
diff --git a/pd/portaudio_v18/pa_beos/pa_beos_mk.cc b/pd/portaudio_v18/pa_beos/pa_beos_mk.cc
deleted file mode 100644
index ff35cdc3..00000000
--- a/pd/portaudio_v18/pa_beos/pa_beos_mk.cc
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * $Id: pa_beos_mk.cc,v 1.1.1.1 2002/01/22 00:52:09 phil Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * BeOS Media Kit Implementation by Joshua Haberman
- *
- * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <be/app/Application.h>
-#include <be/kernel/OS.h>
-#include <be/media/RealtimeAlloc.h>
-#include <be/media/MediaRoster.h>
-#include <be/media/TimeSource.h>
-
-#include <stdio.h>
-#include <string.h>
-
-#include "portaudio.h"
-#include "pa_host.h"
-
-#include "PlaybackNode.h"
-
-#define PRINT(x) { printf x; fflush(stdout); }
-
-#ifdef DEBUG
-#define DBUG(x) PRINT(x)
-#else
-#define DBUG(x)
-#endif
-
-typedef struct PaHostSoundControl
-{
- /* These members are common to all modes of operation */
- media_node pahsc_TimeSource; /* the sound card's DAC. */
- media_format pahsc_Format;
-
- /* These methods are specific to playing mode */
- media_node pahsc_OutputNode; /* output to the mixer */
- media_node pahsc_InputNode; /* reads data from user callback -- PA specific */
-
- media_input pahsc_MixerInput; /* input jack on the soundcard's mixer. */
- media_output pahsc_PaOutput; /* output jack from the PA node */
-
- PaPlaybackNode *pahsc_InputNodeInstance;
-
-}
-PaHostSoundControl;
-
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultOutputDeviceID( void )
-{
- /* stub */
- return 0;
-}
-
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultInputDeviceID( void )
-{
- /* stub */
- return 0;
-}
-
-/*************************************************************************/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
-{
- /* stub */
- return NULL;
-}
-
-/*************************************************************************/
-int Pa_CountDevices()
-{
- /* stub */
- return 1;
-}
-
-/*************************************************************************/
-PaError PaHost_Init( void )
-{
- /* we have to create this in order to use BMediaRoster. I hope it doesn't
- * cause problems */
- be_app = new BApplication("application/x-vnd.portaudio-app");
-
- return paNoError;
-}
-
-PaError PaHost_Term( void )
-{
- delete be_app;
- return paNoError;
-}
-
-/*************************************************************************/
-PaError PaHost_StreamActive( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
- DBUG(("IsRunning returning: %s\n",
- pahsc->pahsc_InputNodeInstance->IsRunning() ? "true" : "false"));
-
- return (PaError)pahsc->pahsc_InputNodeInstance->IsRunning();
-}
-
-PaError PaHost_StartOutput( internalPortAudioStream *past )
-{
- return paNoError;
-}
-
-/*************************************************************************/
-PaError PaHost_StartInput( internalPortAudioStream *past )
-{
- return paNoError;
-}
-
-/*************************************************************************/
-PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
-{
- return paNoError;
-}
-
-/*************************************************************************/
-PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
-{
- return paNoError;
-}
-
-
-/*************************************************************************/
-PaError PaHost_StartEngine( internalPortAudioStream *past )
-{
- bigtime_t very_soon, start_latency;
- status_t err;
- BMediaRoster *roster = BMediaRoster::Roster(&err);
- PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
-
- /* for some reason, err indicates an error (though nothing it wrong)
- * when the DBUG macro in pa_lib.c is enabled. It's reproducably
- * linked. Weird. */
- if( !roster /* || err != B_OK */ )
- {
- DBUG(("No media server! err=%d, roster=%x\n", err, roster));
- return paHostError;
- }
-
- /* tell the node when to start -- since there aren't any other nodes
- * starting that we have to wait for, just tell it to start now
- */
-
- BTimeSource *timeSource = roster->MakeTimeSourceFor(pahsc->pahsc_TimeSource);
- very_soon = timeSource->PerformanceTimeFor( BTimeSource::RealTime() );
- timeSource->Release();
-
- /* Add the latency of starting the network of nodes */
- err = roster->GetStartLatencyFor( pahsc->pahsc_TimeSource, &start_latency );
- very_soon += start_latency;
-
- err = roster->StartNode( pahsc->pahsc_InputNode, very_soon );
- /* No need to start the mixer -- it's always running */
-
- return paNoError;
-}
-
-
-/*************************************************************************/
-PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
- BMediaRoster *roster = BMediaRoster::Roster();
-
- if( !roster )
- {
- DBUG(("No media roster!\n"));
- return paHostError;
- }
-
- if( !pahsc )
- return paHostError;
-
- /* this crashes, and I don't know why yet */
- // if( abort )
- // pahsc->pahsc_InputNodeInstance->mAborted = true;
-
- roster->StopNode(pahsc->pahsc_InputNode, 0, /* immediate = */ true);
-
- return paNoError;
-}
-
-
-/*************************************************************************/
-PaError PaHost_OpenStream( internalPortAudioStream *past )
-{
- status_t err;
- BMediaRoster *roster = BMediaRoster::Roster(&err);
- PaHostSoundControl *pahsc;
-
- /* Allocate and initialize host data. */
- pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
- if( pahsc == NULL )
- {
- goto error;
- }
- memset( pahsc, 0, sizeof(PaHostSoundControl) );
- past->past_DeviceData = (void *) pahsc;
-
- if( !roster /* || err != B_OK */ )
- {
- /* no media server! */
- DBUG(("No media server.\n"));
- goto error;
- }
-
- if ( past->past_NumInputChannels > 0 && past->past_NumOutputChannels > 0 )
- {
- /* filter -- not implemented yet */
- goto error;
- }
- else if ( past->past_NumInputChannels > 0 )
- {
- /* recorder -- not implemented yet */
- goto error;
- }
- else
- {
- /* player ****************************************************************/
-
- status_t err;
- int32 num;
-
- /* First we need to create the three components (like components in a stereo
- * system). The mixer component is our interface to the sound card, data
- * we write there will get played. The BePA_InputNode component is the node
- * which represents communication with the PA client (it is what calls the
- * client's callbacks). The time source component is the sound card's DAC,
- * which allows us to slave the other components to it instead of the system
- * clock. */
- err = roster->GetAudioMixer( &pahsc->pahsc_OutputNode );
- if( err != B_OK )
- {
- DBUG(("Couldn't get default mixer.\n"));
- goto error;
- }
-
- err = roster->GetTimeSource( &pahsc->pahsc_TimeSource );
- if( err != B_OK )
- {
- DBUG(("Couldn't get time source.\n"));
- goto error;
- }
-
- pahsc->pahsc_InputNodeInstance = new PaPlaybackNode(2, 44100,
- past->past_FramesPerUserBuffer, past->past_Callback, past->past_UserData );
- pahsc->pahsc_InputNodeInstance->SetSampleFormat(0,
- past->past_OutputSampleFormat);
- err = roster->RegisterNode( pahsc->pahsc_InputNodeInstance );
- if( err != B_OK )
- {
- DBUG(("Unable to register node.\n"));
- goto error;
- }
-
- roster->GetNodeFor( pahsc->pahsc_InputNodeInstance->Node().node,
- &pahsc->pahsc_InputNode );
- if( err != B_OK )
- {
- DBUG(("Unable to get input node.\n"));
- goto error;
- }
-
- /* Now we have three components (nodes) sitting next to each other. The
- * next step is to look at them and find their inputs and outputs so we can
- * wire them together. */
- err = roster->GetFreeInputsFor( pahsc->pahsc_OutputNode,
- &pahsc->pahsc_MixerInput, 1, &num, B_MEDIA_RAW_AUDIO );
- if( err != B_OK || num < 1 )
- {
- DBUG(("Couldn't get the mixer input.\n"));
- goto error;
- }
-
- err = roster->GetFreeOutputsFor( pahsc->pahsc_InputNode,
- &pahsc->pahsc_PaOutput, 1, &num, B_MEDIA_RAW_AUDIO );
- if( err != B_OK || num < 1 )
- {
- DBUG(("Couldn't get PortAudio output.\n"));
- goto error;
- }
-
-
- /* We've found the input and output -- the final step is to run a wire
- * between them so they are connected. */
-
- /* try to make the mixer input adapt to what PA sends it */
- pahsc->pahsc_Format = pahsc->pahsc_PaOutput.format;
- roster->Connect( pahsc->pahsc_PaOutput.source,
- pahsc->pahsc_MixerInput.destination, &pahsc->pahsc_Format,
- &pahsc->pahsc_PaOutput, &pahsc->pahsc_MixerInput );
-
-
- /* Actually, there's one final step -- tell them all to sync to the
- * sound card's DAC */
- roster->SetTimeSourceFor( pahsc->pahsc_InputNode.node,
- pahsc->pahsc_TimeSource.node );
- roster->SetTimeSourceFor( pahsc->pahsc_OutputNode.node,
- pahsc->pahsc_TimeSource.node );
-
- }
-
- return paNoError;
-
-error:
- PaHost_CloseStream( past );
- return paHostError;
-}
-
-/*************************************************************************/
-PaError PaHost_CloseStream( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
- status_t err;
- BMediaRoster *roster = BMediaRoster::Roster(&err);
-
- if( !roster )
- {
- DBUG(("Couldn't get media roster\n"));
- return paHostError;
- }
-
- if( !pahsc )
- return paHostError;
-
- /* Disconnect all the connections we made when opening the stream */
-
- roster->Disconnect(pahsc->pahsc_InputNode.node, pahsc->pahsc_PaOutput.source,
- pahsc->pahsc_OutputNode.node, pahsc->pahsc_MixerInput.destination);
-
- DBUG(("Calling ReleaseNode()"));
- roster->ReleaseNode(pahsc->pahsc_InputNode);
-
- /* deleting the node shouldn't be necessary -- it is reference counted, and will
- * delete itself when its references drop to zero. the call to ReleaseNode()
- * above should decrease its reference count */
- pahsc->pahsc_InputNodeInstance = NULL;
-
- return paNoError;
-}
-
-/*************************************************************************/
-PaTimestamp Pa_StreamTime( PortAudioStream *stream )
-{
- internalPortAudioStream *past = (internalPortAudioStream *) stream;
- PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
-
- return pahsc->pahsc_InputNodeInstance->GetStreamTime();
-}
-
-/*************************************************************************/
-void Pa_Sleep( long msec )
-{
- /* snooze() takes microseconds */
- snooze( msec * 1000 );
-}
-
-/*************************************************************************
- * Allocate memory that can be accessed in real-time.
- * This may need to be held in physical memory so that it is not
- * paged to virtual memory.
- * This call MUST be balanced with a call to PaHost_FreeFastMemory().
- * Memory will be set to zero.
- */
-void *PaHost_AllocateFastMemory( long numBytes )
-{
- /* BeOS supports non-pagable memory through pools -- a pool is an area
- * of physical memory that is locked. It would be best to pre-allocate
- * that pool and then hand out memory from it, but we don't know in
- * advance how much we'll need. So for now, we'll allocate a pool
- * for every request we get, storing a pointer to the pool at the
- * beginning of the allocated memory */
- rtm_pool *pool;
- void *addr;
- long size = numBytes + sizeof(rtm_pool *);
- static int counter = 0;
- char pool_name[100];
-
- /* Every pool needs a unique name. */
- sprintf(pool_name, "PaPoolNumber%d", counter++);
-
- if( rtm_create_pool( &pool, size, pool_name ) != B_OK )
- return 0;
-
- addr = rtm_alloc( pool, size );
- if( addr == NULL )
- return 0;
-
- memset( addr, 0, numBytes );
- *((rtm_pool **)addr) = pool; // store the pointer to the pool
- addr = (rtm_pool **)addr + 1; // and return the next location in memory
-
- return addr;
-}
-
-/*************************************************************************
- * Free memory that could be accessed in real-time.
- * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
- */
-void PaHost_FreeFastMemory( void *addr, long numBytes )
-{
- rtm_pool *pool;
-
- if( addr == NULL )
- return;
-
- addr = (rtm_pool **)addr - 1;
- pool = *((rtm_pool **)addr);
-
- rtm_free( addr );
- rtm_delete_pool( pool );
-}