📄 playbacknode.cc
字号:
/*
* $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
*
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -