From 2e416ee0095f1bf608f849f156d564e0f45fb8ab Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Mon, 2 Feb 2004 12:18:59 +0000 Subject: merged in version_0_37_1test6 svn path=/trunk/; revision=1305 --- pd/portaudio/pa_beos/PlaybackNode.cc | 538 ----------------------------------- pd/portaudio/pa_beos/PlaybackNode.h | 108 ------- pd/portaudio/pa_beos/pa_beos_mk.cc | 441 ---------------------------- 3 files changed, 1087 deletions(-) delete mode 100644 pd/portaudio/pa_beos/PlaybackNode.cc delete mode 100644 pd/portaudio/pa_beos/PlaybackNode.h delete mode 100644 pd/portaudio/pa_beos/pa_beos_mk.cc (limited to 'pd/portaudio/pa_beos') diff --git a/pd/portaudio/pa_beos/PlaybackNode.cc b/pd/portaudio/pa_beos/PlaybackNode.cc deleted file mode 100644 index 41cbae34..00000000 --- a/pd/portaudio/pa_beos/PlaybackNode.cc +++ /dev/null @@ -1,538 +0,0 @@ -/* - * $Id: PlaybackNode.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger 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 - * - * 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 - -#include -#include -#include - -#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/pa_beos/PlaybackNode.h b/pd/portaudio/pa_beos/PlaybackNode.h deleted file mode 100644 index db978a59..00000000 --- a/pd/portaudio/pa_beos/PlaybackNode.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * $Id: PlaybackNode.h,v 1.1.1.1 2003-05-09 16:03:53 ggeiger 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 - * - * 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 -#include -#include - -#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/pa_beos/pa_beos_mk.cc b/pd/portaudio/pa_beos/pa_beos_mk.cc deleted file mode 100644 index 3307a2ff..00000000 --- a/pd/portaudio/pa_beos/pa_beos_mk.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * $Id: pa_beos_mk.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger 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 - * - * 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 -#include -#include -#include -#include - -#include -#include - -#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 ); -} -- cgit v1.2.1