From 08c82102cfa929042c6f33aa2e9b9edab276f5be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Wed, 11 Jun 2008 22:24:34 +0000 Subject: [PATCH] Work in progress: * Cleaning up and refactoring the OpenSoundNode code to use a single coding style and be less C-like in many places. * Fixed quite a few memory leaks in OpenSoundNode. * Removed large chunks of inactive code originating from the MultiAudioNode. * Transfered some functionality into NodeInput and NodeOutput, could be more. * No functional changes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25932 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../opensound/OpenSoundAddOn.cpp | 6 +- .../media-add-ons/opensound/OpenSoundDevice.h | 5 +- .../opensound/OpenSoundDeviceEngine.cpp | 21 +- .../media-add-ons/opensound/OpenSoundNode.cpp | 2641 ++++++----------- .../media-add-ons/opensound/OpenSoundNode.h | 622 ++-- 5 files changed, 1226 insertions(+), 2069 deletions(-) diff --git a/src/add-ons/media/media-add-ons/opensound/OpenSoundAddOn.cpp b/src/add-ons/media/media-add-ons/opensound/OpenSoundAddOn.cpp index 0b80f0a544..a71b58bc78 100644 --- a/src/add-ons/media/media-add-ons/opensound/OpenSoundAddOn.cpp +++ b/src/add-ons/media/media-add-ons/opensound/OpenSoundAddOn.cpp @@ -7,6 +7,7 @@ * Based on MultiAudio media addon * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) */ +#include "OpenSoundAddOn.h" #include #include @@ -22,8 +23,8 @@ #include #include "OpenSoundNode.h" -#include "OpenSoundAddOn.h" #include "OpenSoundDevice.h" +#include "OpenSoundDeviceEngine.h" #include #include @@ -119,7 +120,8 @@ BMediaNode * OpenSoundAddOn::InstantiateNodeFor( { CALLED(); - OpenSoundDevice *device = (OpenSoundDevice*)fDevices.ItemAt(info->internal_id); + OpenSoundDevice *device = (OpenSoundDevice*)fDevices.ItemAt( + info->internal_id); if (device == NULL) { *out_error = B_ERROR; return NULL; diff --git a/src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h b/src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h index bd4ca61b99..7dc0898757 100644 --- a/src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h +++ b/src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h @@ -22,10 +22,7 @@ #define MAX_CHANNELS 32 #define NB_BUFFERS 32 -//#define DEFAULT_BUFFER_SIZE 2048 -//#define DEFAULT_BUFFER_SIZE (32*1024) -//#define DEFAULT_BUFFER_SIZE (16*1024) -#define DEFAULT_BUFFER_SIZE (2*1024) +#define DEFAULT_BUFFER_SIZE 2048 /* define to support encoded audio (AC3, MPEG, ...) when the card supports it */ //#define ENABLE_NON_RAW_SUPPORT 1 diff --git a/src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp b/src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp index 86c0117a9a..b2b4291309 100644 --- a/src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp +++ b/src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp @@ -93,7 +93,7 @@ status_t OpenSoundDeviceEngine::Open(int mode) Close(); return EIO; } -#if 0 +#if 1 // set fragments v = 0x7fff0000 | 0x000b; // unlimited * 2048 if (ioctl(fFD, SNDCTL_DSP_SETFRAGMENT, &v, sizeof(int)) < 0) { @@ -193,22 +193,27 @@ status_t OpenSoundDeviceEngine::UpdateInfo(void) } -bigtime_t OpenSoundDeviceEngine::PlaybackLatency(void) +bigtime_t +OpenSoundDeviceEngine::PlaybackLatency() { bigtime_t latency; int delay; delay = GetODelay(); - delay = 0; //XXX - latency = ((double)delay * 1000000LL - / (fMediaFormat.u.raw_audio.channel_count * fMediaFormat.u.raw_audio.frame_rate - * (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK))); - PRINT(("PlaybackLatency: odelay %d latency %Ld card %Ld\n", delay, latency, CardLatency())); +delay = 0; //XXX + latency = (bigtime_t)((double)delay * 1000000LL + / (fMediaFormat.u.raw_audio.channel_count + * fMediaFormat.u.raw_audio.frame_rate + * (fMediaFormat.AudioFormat() + & media_raw_audio_format::B_AUDIO_SIZE_MASK))); + PRINT(("PlaybackLatency: odelay %d latency %Ld card %Ld\n", delay, latency, + CardLatency())); latency += CardLatency(); return latency; } -bigtime_t OpenSoundDeviceEngine::RecordingLatency(void) +bigtime_t +OpenSoundDeviceEngine::RecordingLatency() { return 0LL; //XXX } diff --git a/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp b/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp index a8815c29be..dfbd8fc974 100644 --- a/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp +++ b/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp @@ -2,138 +2,222 @@ * OpenSound media addon for BeOS and Haiku * * Copyright (c) 2007, François Revol (revol@free.fr) - * Distributed under the terms of the MIT License. - * - * Based on MultiAudio media addon * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) - * - * All rights reserved. - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 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. - * + * Distributed under the terms of the MIT License. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "OpenSoundNode.h" + #include +#include +#include +#include +#include +#include #include + #include #include +#include +#include -#include "OpenSoundNode.h" -#include "driver_io.h" #ifdef DEBUG #define PRINTING #endif #include "debug.h" -#include -#include +#include "OpenSoundDevice.h" +#include "OpenSoundDeviceEngine.h" +#include "OpenSoundDeviceMixer.h" -const char * multi_string[] = -{ - "NAME IS ATTACHED", - "Output", "Input", "Setup", "Tone Control", "Extended Setup", "Enhanced Setup", "Master", - "Beep", "Phone", "Mic", "Line", "CD", "Video", "Aux", "Wave", "Gain", "Level", "Volume", - "Mute", "Enable", "Stereo Mix", "Mono Mix", "Output Stereo Mix", "Output Mono Mix", "Output Bass", - "Output Treble", "Output 3D Center", "Output 3D Depth" + +class OpenSoundNode::NodeInput { +public: + NodeInput(const media_input& input, const media_format& format) + : fNode(NULL), + fEngineIndex(-1), + fRealEngine(NULL), + fOSSFormatFlags(0), + + fInput(input), + fPreferredFormat(format), + + fThread(-1), + fBufferCycle(1), + + fBuffers(4) + { + CALLED(); + } + + ~NodeInput() + { + CALLED(); + } + + status_t FillBuffer(BBuffer* buffer) + { + CALLED(); + + ssize_t written = fRealEngine->Write( + buffer->Data(), buffer->SizeUsed()); + + if (written < 0) + return (status_t)written; + if (written < buffer->SizeUsed()) + return B_IO_ERROR; + return B_OK; + } + + void WriteSilence(size_t bytes) + { + CALLED(); + + // TODO: A silenceBuffer could be cached! + uint8 formatSilence = 0; + if (fInput.format.u.raw_audio.format + == media_raw_audio_format::B_AUDIO_UCHAR) + formatSilence = 128; + + size_t bufferSize = 2048; + char buffer[bufferSize]; + + memset(buffer, formatSilence, bufferSize); + + while (bytes) { + size_t chunk = MIN(bytes, bufferSize); + ssize_t written = fRealEngine->Write(buffer, chunk); + if (written < 0) + return; + bytes -= written; + } + } + + OpenSoundNode* fNode; + int32 fEngineIndex; + OpenSoundDeviceEngine* fRealEngine; + // engine it's connected to. can be a shadow one (!= fEngineIndex) + int fOSSFormatFlags; + // AFMT_* flags for this input + media_input fInput; + media_format fPreferredFormat; + + thread_id fThread; + uint32 fBufferCycle; + BList fBuffers; + // contains BBuffer* pointers that have not yet played }; -node_input::node_input(media_input &input, media_format format) -{ - CALLED(); - fNode = NULL; - fEngineId = -1; - fRealEngine = NULL; - fAFmt = 0; - fInput = input; - fPreferredFormat = format; - fBufferCycle = 1; - //fBuffer = NULL; - fThread = -1; -} -node_input::~node_input() -{ - CALLED(); -} +class OpenSoundNode::NodeOutput { +public: + NodeOutput(const media_output& output, const media_format& format) + : fNode(NULL), + fEngineIndex(-1), + fRealEngine(NULL), + fOSSFormatFlags(0), -node_output::node_output(media_output &output, media_format format) - : fBufferGroup(NULL), - fOutputEnabled(true) -{ - CALLED(); - fNode = NULL; - fEngineId = -1; - fRealEngine = NULL; - fAFmt = 0; - fOutput = output; - fPreferredFormat = format; - fBufferCycle = 1; - fThread = -1; -} + fOutput(output), + fPreferredFormat(format), -node_output::~node_output() -{ - CALLED(); -} + fThread(-1), + fBufferGroup(NULL), + fOutputEnabled(true), + + fSamplesSent(0), + fBufferCycle(1) + { + CALLED(); + } + + ~NodeOutput() + { + CALLED(); + } + + BBuffer* FillNextBuffer(bigtime_t bufferDuration) + { + if (fBufferGroup == NULL) + return NULL; + + BBuffer* buffer = fBufferGroup->RequestBuffer( + fOutput.format.u.raw_audio.buffer_size, bufferDuration); + + // if we fail to get a buffer (for example, if the request times out), + // we skip this buffer and go on to the next, to avoid locking up the + // control thread + if (!buffer) + return NULL; + + // now fill it with data + ssize_t sizeUsed = fRealEngine->Read(buffer->Data(), + fOutput.format.u.raw_audio.buffer_size); + if (sizeUsed < 0) { + PRINT(("NodeOutput::%s: %s\n", __FUNCTION__, + strerror(sizeUsed))); + buffer->Recycle(); + return NULL; + } + if (sizeUsed < fOutput.format.u.raw_audio.buffer_size) { + PRINT(("NodeOutput::%s: requested %d, got %d\n", __FUNCTION__, + fOutput.format.u.raw_audio.buffer_size, sizeUsed)); + } + + media_header* hdr = buffer->Header(); + if (hdr != NULL) { + hdr->type = B_MEDIA_RAW_AUDIO; + hdr->size_used = sizeUsed; + } + + return buffer; + } + + OpenSoundNode* fNode; + int32 fEngineIndex; + OpenSoundDeviceEngine* fRealEngine; + // engine it's connected to. can be a shadow one (!= fEngineIndex) + int fOSSFormatFlags; + // AFMT_* flags for this output + media_output fOutput; + media_format fPreferredFormat; + + thread_id fThread; + BBufferGroup* fBufferGroup; + bool fOutputEnabled; + uint64 fSamplesSent; + volatile uint32 fBufferCycle; +}; -// -------------------------------------------------------- // -// ctor/dtor -// -------------------------------------------------------- // +// #pragma mark - OpenSoundNode -OpenSoundNode::~OpenSoundNode(void) + +OpenSoundNode::~OpenSoundNode() { CALLED(); fAddOn->GetConfigurationFor(this, NULL); - - //StopThread(); + + int32 count = fInputs.CountItems(); + for (int32 i = 0; i < count; i++) + delete (NodeInput*)fInputs.ItemAtFast(i); + count = fOutputs.CountItems(); + for (int32 i = 0; i < count; i++) + delete (NodeOutput*)fOutputs.ItemAtFast(i); + BMediaEventLooper::Quit(); fWeb = NULL; } -OpenSoundNode::OpenSoundNode(BMediaAddOn *addon, char* name, OpenSoundDevice *device, - int32 internal_id, BMessage * config) + +OpenSoundNode::OpenSoundNode(BMediaAddOn* addon, const char* name, + OpenSoundDevice* device, int32 internal_id, BMessage* config) : BMediaNode(name), BBufferConsumer(B_MEDIA_RAW_AUDIO), BBufferProducer(B_MEDIA_RAW_AUDIO), BTimeSource(), BMediaEventLooper(), - fThread(-1), + + fInitCheckStatus(B_NO_INIT), fDevice(device), fTimeSourceStarted(false), fOldPlayedFramesCount(0LL), @@ -142,67 +226,65 @@ OpenSoundNode::OpenSoundNode(BMediaAddOn *addon, char* name, OpenSoundDevice *de fConfig(*config) { CALLED(); - fInitCheckStatus = B_NO_INIT; - if(!device) + if (fDevice == NULL) return; fAddOn = addon; fId = internal_id; - AddNodeKind( B_PHYSICAL_OUTPUT ); - AddNodeKind( B_PHYSICAL_INPUT ); + AddNodeKind(B_PHYSICAL_OUTPUT); + AddNodeKind(B_PHYSICAL_INPUT); // initialize our preferred format object - //XXX: this should go away! should use engine's preferred for each afmt. + // TODO: this should go away! should use engine's preferred for each afmt. #if 1 - memset(&fPreferredFormat, 0, sizeof(fPreferredFormat)); // set everything to wildcard first + memset(&fPreferredFormat, 0, sizeof(fPreferredFormat)); + // set everything to wildcard first fPreferredFormat.type = B_MEDIA_RAW_AUDIO; fPreferredFormat.u.raw_audio = media_multi_audio_format::wildcard; fPreferredFormat.u.raw_audio.channel_count = 2; fPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; OpenSoundDeviceEngine *engine = fDevice->EngineAt(0); if (engine) { - const oss_audioinfo *ai = engine->Info(); + const oss_audioinfo* ai = engine->Info(); int fmt = OpenSoundDevice::select_oss_format(ai->oformats); - fPreferredFormat.u.raw_audio.format = OpenSoundDevice::convert_oss_format_to_media_format(fmt); - fPreferredFormat.u.raw_audio.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(fmt); - //XXX:engine->PreferredChannels() ? (caps & DSP_CH*) - fPreferredFormat.u.raw_audio.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(ai->max_rate); // measured in Hertz + fPreferredFormat.u.raw_audio.format + = OpenSoundDevice::convert_oss_format_to_media_format(fmt); + fPreferredFormat.u.raw_audio.valid_bits + = OpenSoundDevice::convert_oss_format_to_valid_bits(fmt); + // TODO: engine->PreferredChannels() ? (caps & DSP_CH*) + fPreferredFormat.u.raw_audio.frame_rate + = OpenSoundDevice::convert_oss_rate_to_media_rate(ai->max_rate); // measured in Hertz } - // we'll use the consumer's preferred buffer size, if any -#if MA - fPreferredFormat.u.raw_audio.buffer_size = fDevice->MBL.return_record_buffer_size - * (fPreferredFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) - * fPreferredFormat.u.raw_audio.channel_count; -#endif - //XXX: SNDCTL_DSP_GETBLKSIZE ? + // TODO: Use the OSS suggested buffer size via SNDCTL_DSP_GETBLKSIZE ? fPreferredFormat.u.raw_audio.buffer_size = DEFAULT_BUFFER_SIZE - * (fPreferredFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) - * fPreferredFormat.u.raw_audio.channel_count; + * (fPreferredFormat.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK) + * fPreferredFormat.u.raw_audio.channel_count; #endif - if(config) { + if (config) PRINT_OBJECT(*config); - } fInitCheckStatus = B_OK; } -status_t OpenSoundNode::InitCheck(void) const + +status_t +OpenSoundNode::InitCheck() const { CALLED(); return fInitCheckStatus; } -// -------------------------------------------------------- // -// implementation of BMediaNode -// -------------------------------------------------------- // +// #pragma mark - BMediaNode -BMediaAddOn * OpenSoundNode::AddOn( - int32 * internal_id) const + +BMediaAddOn* +OpenSoundNode::AddOn(int32* internal_id) const { CALLED(); // BeBook says this only gets called if we were in an add-on. @@ -215,26 +297,27 @@ BMediaAddOn * OpenSoundNode::AddOn( return fAddOn; } -void OpenSoundNode::Preroll(void) + +void +OpenSoundNode::Preroll() { CALLED(); // XXX:Performance opportunity BMediaNode::Preroll(); } -status_t OpenSoundNode::HandleMessage( - int32 message, - const void * data, - size_t size) + +status_t +OpenSoundNode::HandleMessage(int32 message, const void* data, size_t size) { CALLED(); return B_ERROR; } -void OpenSoundNode::NodeRegistered(void) + +void +OpenSoundNode::NodeRegistered() { - status_t err; - int i, f, fmt; CALLED(); if (fInitCheckStatus != B_OK) { @@ -246,9 +329,8 @@ void OpenSoundNode::NodeRegistered(void) Run(); - node_input *currentInput = NULL; PRINT(("NodeRegistered: %d engines\n", fDevice->CountEngines())); - for (i = 0; i < fDevice->CountEngines(); i++) { + for (int32 i = 0; i < fDevice->CountEngines(); i++) { OpenSoundDeviceEngine *engine = fDevice->EngineAt(i); if (!engine) continue; @@ -258,46 +340,48 @@ void OpenSoundNode::NodeRegistered(void) // skip engines that don't have outputs if ((engine->Caps() & PCM_CAP_OUTPUT) == 0) continue; - PRINT(("NodeRegistered: engine[%d]: .caps=0x%08x, .oformats=0x%08x\n", i, engine->Caps(), engine->Info()->oformats)); - for (f = 0; gSupportedFormats[f]; f++) { - fmt = gSupportedFormats[f] & engine->Info()->oformats; + + PRINT(("NodeRegistered: engine[%d]: .caps=0x%08x, .oformats=0x%08x\n", + i, engine->Caps(), engine->Info()->oformats)); + + for (int32 f = 0; gSupportedFormats[f]; f++) { + int fmt = gSupportedFormats[f] & engine->Info()->oformats; if (fmt == 0) continue; - PRINT(("NodeRegistered() : creating an input for engine %i, format[%i]\n", i, f)); - + PRINT(("NodeRegistered() : creating an input for engine %i, " + "format[%i]\n", i, f)); + media_format preferredFormat; - err = engine->PreferredFormatFor(fmt, preferredFormat); + status_t err = engine->PreferredFormatFor(fmt, preferredFormat); if (err < B_OK) continue; - media_input *input = new media_input; + media_input input; //input->format = fPreferredFormat;//XXX - input->format = preferredFormat; - input->destination.port = ControlPort(); - input->destination.id = fInputs.CountItems(); - input->node = Node(); + input.format = preferredFormat; + input.destination.port = ControlPort(); + input.destination.id = fInputs.CountItems(); + input.node = Node(); char *prefix = ""; if (strstr(engine->Info()->name, "SPDIF")) prefix = "S/PDIF "; - sprintf(input->name, "%s%s output %ld", prefix, gSupportedFormatsNames[f], input->destination.id); + sprintf(input.name, "%s%s output %ld", prefix, + gSupportedFormatsNames[f], input.destination.id); - currentInput = new node_input(*input, preferredFormat); - //currentInput->fPreferredFormat.u.raw_audio.channel_count = engine->Info()->max_channels; + NodeInput* currentInput = new NodeInput(input, preferredFormat); currentInput->fInput.format = currentInput->fPreferredFormat; - currentInput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id; - currentInput->fEngineId = i; - currentInput->fAFmt = fmt; + currentInput->fEngineIndex = i; + currentInput->fOSSFormatFlags = fmt; currentInput->fNode = this; fInputs.AddItem(currentInput); - currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format; + currentInput->fInput.format.u.raw_audio.format + = media_raw_audio_format::wildcard.format; } } - node_output *currentOutput = NULL; - - for (i = 0; i < fDevice->CountEngines(); i++) { + for (int32 i = 0; i < fDevice->CountEngines(); i++) { OpenSoundDeviceEngine *engine = fDevice->EngineAt(i); if (!engine) continue; @@ -307,15 +391,19 @@ void OpenSoundNode::NodeRegistered(void) // skip engines that don't have inputs if ((engine->Caps() & PCM_CAP_INPUT) == 0) continue; - PRINT(("NodeRegistered: engine[%d]: .caps=0x%08x, .iformats=0x%08x\n", i, engine->Caps(), engine->Info()->iformats)); - for (f = 0; gSupportedFormats[f]; f++) { - fmt = gSupportedFormats[f] & engine->Info()->iformats; + + PRINT(("NodeRegistered: engine[%d]: .caps=0x%08x, .iformats=0x%08x\n", + i, engine->Caps(), engine->Info()->iformats)); + + for (int32 f = 0; gSupportedFormats[f]; f++) { + int fmt = gSupportedFormats[f] & engine->Info()->iformats; if (fmt == 0) continue; - PRINT(("NodeRegistered() : creating an output for engine %i, format[%i]\n", i, f)); + PRINT(("NodeRegistered() : creating an output for engine %i, " + "format[%i]\n", i, f)); media_format preferredFormat; - err = engine->PreferredFormatFor(fmt, preferredFormat); + status_t err = engine->PreferredFormatFor(fmt, preferredFormat); if (err < B_OK) continue; @@ -330,14 +418,16 @@ void OpenSoundNode::NodeRegistered(void) char *prefix = ""; if (strstr(engine->Info()->name, "SPDIF")) prefix = "S/PDIF "; - sprintf(output->name, "%s%s input %ld", prefix, gSupportedFormatsNames[f], output->source.id); + sprintf(output->name, "%s%s input %ld", prefix, + gSupportedFormatsNames[f], output->source.id); - currentOutput = new node_output(*output, preferredFormat); - //currentOutput->fPreferredFormat.u.raw_audio.channel_count = engine->Info()->max_channels; + NodeOutput* currentOutput = new NodeOutput(*output, + preferredFormat); +// currentOutput->fPreferredFormat.u.raw_audio.channel_count +// = engine->Info()->max_channels; currentOutput->fOutput.format = currentOutput->fPreferredFormat; - currentOutput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id; - currentOutput->fEngineId = i; - currentOutput->fAFmt = fmt; + currentOutput->fEngineIndex = i; + currentOutput->fOSSFormatFlags = fmt; currentOutput->fNode = this; fOutputs.AddItem(currentOutput); } @@ -365,35 +455,40 @@ void OpenSoundNode::NodeRegistered(void) PRINT(("apply configuration in : %ld\n", system_time() - start)); } -status_t OpenSoundNode::RequestCompleted(const media_request_info &info) + +status_t +OpenSoundNode::RequestCompleted(const media_request_info& info) { CALLED(); return B_OK; } -void OpenSoundNode::SetTimeSource(BTimeSource *timeSource) + +void +OpenSoundNode::SetTimeSource(BTimeSource* timeSource) { CALLED(); } -// -------------------------------------------------------- // -// implemention of BBufferConsumer -// -------------------------------------------------------- // -// Check to make sure the format is okay, then remove -// any wildcards corresponding to our requirements. -status_t OpenSoundNode::AcceptFormat( - const media_destination & dest, - media_format * format) +// #pragma mark - BBufferConsumer + + +status_t +OpenSoundNode::AcceptFormat(const media_destination& dest, + media_format* format) { - status_t err; + // Check to make sure the format is okay, then remove + // any wildcards corresponding to our requirements. + CALLED(); - node_input *channel = FindInput(dest); + NodeInput* channel = _FindInput(dest); - if(channel==NULL) { + if (channel == NULL) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); - return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it + return B_MEDIA_BAD_DESTINATION; + // we only have one input so that better be it } if (format == 0) { @@ -412,12 +507,12 @@ status_t OpenSoundNode::AcceptFormat( BAutolock L(fDevice->Locker()); - OpenSoundDeviceEngine *engine = fDevice->NextFreeEngineAt(channel->fEngineId, false); - if (!engine) { + OpenSoundDeviceEngine* engine = fDevice->NextFreeEngineAt( + channel->fEngineIndex, false); + if (!engine) return B_BUSY; - } - err = engine->AcceptFormatFor(channel->fAFmt, *format, false); + status_t err = engine->AcceptFormatFor(channel->fOSSFormatFlags, *format, false); if (err < B_OK) return err; @@ -430,8 +525,8 @@ status_t OpenSoundNode::AcceptFormat( } */ - //channel->fFormat = channel->fPreferredFormat; - channel->fFormat = *format; + //channel->fInput.format = channel->fPreferredFormat; + channel->fInput.format = *format; /*if(format->u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT && channel->fPreferredFormat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) @@ -473,7 +568,7 @@ status_t OpenSoundNode::GetNextInput( } if ((*cookie < fInputs.CountItems()) && (*cookie >= 0)) { - node_input *channel = (node_input *)fInputs.ItemAt(*cookie); + NodeInput *channel = (NodeInput *)fInputs.ItemAt(*cookie); *out_input = channel->fInput; *cookie += 1; PRINT(("input.format : %u\n", channel->fInput.format.u.raw_audio.format)); @@ -532,7 +627,7 @@ void OpenSoundNode::ProducerDataStatus( { /**/CALLED(); - node_input *channel = FindInput(for_whom); + NodeInput *channel = _FindInput(for_whom); if(channel==NULL) { fprintf(stderr,"invalid destination received in OpenSoundNode::ProducerDataStatus\n"); @@ -558,7 +653,7 @@ status_t OpenSoundNode::GetLatencyFor( return B_BAD_VALUE; } - node_input *channel = FindInput(for_whom); + NodeInput *channel = _FindInput(for_whom); if(channel==NULL || channel->fRealEngine==NULL) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); @@ -585,7 +680,7 @@ status_t OpenSoundNode::Connected( return B_BAD_VALUE; // no crashing } - node_input *channel = FindInput(where); + NodeInput *channel = _FindInput(where); if(channel==NULL) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); @@ -610,48 +705,50 @@ status_t OpenSoundNode::Connected( *out_input = channel->fInput; // we are sure the thread is started - //StartThread(); - StartPlayThread(channel); + _StartPlayThread(channel); return B_OK; } -void OpenSoundNode::Disconnected( - const media_source & producer, - const media_destination & where) + +void +OpenSoundNode::Disconnected(const media_source& producer, + const media_destination& where) { CALLED(); - node_input *channel = FindInput(where); - - if(channel==NULL) { - fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + + NodeInput* channel = _FindInput(where); + if (channel == NULL) { + fprintf(stderr,"OpenSoundNode::Disconnected() - " + "B_MEDIA_BAD_DESTINATION\n"); return; } if (channel->fInput.source != producer) { - fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + fprintf(stderr,"OpenSoundNode::Disconnected() - " + "B_MEDIA_BAD_SOURCE\n"); return; } - - StopPlayThread(channel); + + _StopPlayThread(channel); channel->fInput.source = media_source::null; channel->fInput.format = channel->fPreferredFormat; if (channel->fRealEngine) channel->fRealEngine->Close(); channel->fRealEngine = NULL; - FillWithZeros(*channel); //GetFormat(&channel->fInput.format); } - /* The notification comes from the upstream producer, so he's already cool with */ - /* the format; you should not ask him about it in here. */ -status_t OpenSoundNode::FormatChanged( - const media_source & producer, - const media_destination & consumer, - int32 change_tag, - const media_format & format) + +//! The notification comes from the upstream producer, so he's +// already cool with the format; you should not ask him about it +// in here. +status_t +OpenSoundNode::FormatChanged(const media_source& producer, + const media_destination& consumer, int32 change_tag, + const media_format& format) { CALLED(); - node_input *channel = FindInput(consumer); + NodeInput *channel = _FindInput(consumer); if(channel==NULL) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); @@ -664,37 +761,36 @@ status_t OpenSoundNode::FormatChanged( return B_ERROR; } - /* Given a performance time of some previous buffer, retrieve the remembered tag */ - /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ - /* idea being that flags can be added later, and the understood flags returned in */ - /* *out_flags. */ -status_t OpenSoundNode::SeekTagRequested( - const media_destination & destination, - bigtime_t in_target_time, - uint32 in_flags, - media_seek_tag * out_seek_tag, - bigtime_t * out_tagged_time, - uint32 * out_flags) + +//! Given a performance time of some previous buffer, retrieve the +// remembered tag of the closest (previous or exact) performance +// time. Set *out_flags to 0; the idea being that flags can be +// added later, and the understood flags returned in *out_flags. +status_t +OpenSoundNode::SeekTagRequested(const media_destination& destination, + bigtime_t in_target_time, uint32 in_flags, media_seek_tag* out_seek_tag, + bigtime_t* out_tagged_time, uint32* out_flags) { CALLED(); - return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags, - out_seek_tag,out_tagged_time,out_flags); + return BBufferConsumer::SeekTagRequested(destination, in_target_time, + in_flags, out_seek_tag, out_tagged_time, out_flags); } -// -------------------------------------------------------- // -// implementation for BBufferProducer -// -------------------------------------------------------- // +// #pragma mark - BBufferProducer + + +//! FormatSuggestionRequested() is not necessarily part of the format +// negotiation process; it's simply an interrogation -- the caller wants +// to see what the node's preferred data format is, given a suggestion by +// the caller. status_t -OpenSoundNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, media_format* format) +OpenSoundNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, + media_format* format) { - // FormatSuggestionRequested() is not necessarily part of the format negotiation - // process; it's simply an interrogation -- the caller wants to see what the node's - // preferred data format is, given a suggestion by the caller. CALLED(); - if (!format) - { + if (!format) { fprintf(stderr, "\tERROR - NULL format pointer passed in!\n"); return B_BAD_VALUE; } @@ -703,55 +799,69 @@ OpenSoundNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, med *format = fPreferredFormat; // a wildcard type is okay; we can specialize it - if (type == B_MEDIA_UNKNOWN_TYPE) type = B_MEDIA_RAW_AUDIO; + if (type == B_MEDIA_UNKNOWN_TYPE) + type = B_MEDIA_RAW_AUDIO; - // we only support raw audio - if (type != B_MEDIA_RAW_AUDIO) return B_MEDIA_BAD_FORMAT; - else return B_OK; + // TODO: For OSS engines that support encoded formats, we could + // handle this here. For the time being, we only support raw audio. + if (type != B_MEDIA_RAW_AUDIO) + return B_MEDIA_BAD_FORMAT; + + return B_OK; } + +//! FormatProposal() is the first stage in the BMediaRoster::Connect() +// process. We hand out a suggested format, with wildcards for any +// variations we support. status_t OpenSoundNode::FormatProposal(const media_source& output, media_format* format) { - status_t err; - // FormatProposal() is the first stage in the BMediaRoster::Connect() process. We hand - // out a suggested format, with wildcards for any variations we support. CALLED(); - node_output *channel = FindOutput(output); + + NodeOutput* channel = _FindOutput(output); // is this a proposal for our select output? - if (channel == NULL) - { - fprintf(stderr, "OpenSoundNode::FormatProposal returning B_MEDIA_BAD_SOURCE\n"); + if (channel == NULL) { + fprintf(stderr, "OpenSoundNode::FormatProposal returning " + "B_MEDIA_BAD_SOURCE\n"); return B_MEDIA_BAD_SOURCE; } media_type requestedType = format->type; #ifdef ENABLE_REC - OpenSoundDeviceEngine *engine = fDevice->NextFreeEngineAt(channel->fEngineId, true); + OpenSoundDeviceEngine* engine = fDevice->NextFreeEngineAt( + channel->fEngineIndex, true); - // we only support floating-point raw audio, so we always return that, but we - // supply an error code depending on whether we found the proposal acceptable. - err = engine->PreferredFormatFor(channel->fAFmt, *format, true); + // We only support raw audio, so we always return that, but we supply an + // error code depending on whether we found the proposal acceptable. + status_t err = engine->PreferredFormatFor(channel->fOSSFormatFlags, *format, true); if (err < B_OK) return err; #else *format = fPreferredFormat; #endif - if ((requestedType != B_MEDIA_UNKNOWN_TYPE) && (requestedType != B_MEDIA_RAW_AUDIO) + if (requestedType != B_MEDIA_UNKNOWN_TYPE + && requestedType != B_MEDIA_RAW_AUDIO #ifdef ENABLE_NON_RAW_SUPPORT - && (requestedType != B_MEDIA_ENCODED_AUDIO) + && requestedType != B_MEDIA_ENCODED_AUDIO #endif ) { - fprintf(stderr, "OpenSoundNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n"); + fprintf(stderr, "OpenSoundNode::FormatProposal returning " + "B_MEDIA_BAD_FORMAT\n"); return B_MEDIA_BAD_FORMAT; } - else return B_OK; // raw audio or wildcard type, either is okay by us + + // raw audio or wildcard type, either is okay by us + return B_OK; } + status_t -OpenSoundNode::FormatChangeRequested(const media_source& source, const media_destination& destination, media_format* io_format, int32* _deprecated_) +OpenSoundNode::FormatChangeRequested(const media_source& source, + const media_destination& destination, media_format* io_format, + int32* _deprecated_) { CALLED(); @@ -759,20 +869,22 @@ OpenSoundNode::FormatChangeRequested(const media_source& source, const media_des return B_ERROR; } + status_t OpenSoundNode::GetNextOutput(int32* cookie, media_output* out_output) { CALLED(); - if ((*cookie < fOutputs.CountItems()) && (*cookie >= 0)) { - node_output *channel = (node_output *)fOutputs.ItemAt(*cookie); - *out_output = channel->fOutput; - *cookie += 1; - return B_OK; - } else + if (*cookie >= fOutputs.CountItems() || *cookie < 0) return B_BAD_INDEX; + + NodeOutput *channel = (NodeOutput*)fOutputs.ItemAt(*cookie); + *out_output = channel->fOutput; + *cookie += 1; + return B_OK; } + status_t OpenSoundNode::DisposeOutputCookie(int32 cookie) { @@ -781,37 +893,37 @@ OpenSoundNode::DisposeOutputCookie(int32 cookie) return B_OK; } + status_t -OpenSoundNode::SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup) +OpenSoundNode::SetBufferGroup(const media_source& for_source, + BBufferGroup* newGroup) { CALLED(); - node_output *channel = FindOutput(for_source); + NodeOutput* channel = _FindOutput(for_source); // is this our output? - if (channel == NULL) - { - fprintf(stderr, "OpenSoundNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n"); + if (channel == NULL) { + fprintf(stderr, "OpenSoundNode::SetBufferGroup() returning " + "B_MEDIA_BAD_SOURCE\n"); return B_MEDIA_BAD_SOURCE; } // Are we being passed the buffer group we're already using? if (newGroup == channel->fBufferGroup) return B_OK; - // Ahh, someone wants us to use a different buffer group. At this point we delete - // the one we are using and use the specified one instead. If the specified group is - // NULL, we need to recreate one ourselves, and use *that*. Note that if we're - // caching a BBuffer that we requested earlier, we have to Recycle() that buffer - // *before* deleting the buffer group, otherwise we'll deadlock waiting for that - // buffer to be recycled! - delete channel->fBufferGroup; // waits for all buffers to recycle - if (newGroup != NULL) - { + // Ahh, someone wants us to use a different buffer group. At this point + // we delete the one we are using and use the specified one instead. If + // the specified group is NULL, we need to recreate one ourselves, and + // use *that*. Note that if we're caching a BBuffer that we requested + // earlier, we have to Recycle() that buffer *before* deleting the buffer + // group, otherwise we'll deadlock waiting for that buffer to be recycled! + delete channel->fBufferGroup; + // waits for all buffers to recycle + if (newGroup != NULL) { // we were given a valid group; just use that one from now on channel->fBufferGroup = newGroup; - } - else - { + } else { // we were passed a NULL group pointer; that means we construct // our own buffer group to use from now on size_t size = channel->fOutput.format.u.raw_audio.buffer_size; @@ -822,23 +934,27 @@ OpenSoundNode::SetBufferGroup(const media_source& for_source, BBufferGroup* newG return B_OK; } + +//! PrepareToConnect() is the second stage of format negotiations that happens +// inside BMediaRoster::Connect(). At this point, the consumer's +// AcceptFormat() method has been called, and that node has potentially +// changed the proposed format. It may also have left wildcards in the +// format. PrepareToConnect() *must* fully specialize the format before +// returning! status_t -OpenSoundNode::PrepareToConnect(const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name) +OpenSoundNode::PrepareToConnect(const media_source& what, + const media_destination& where, media_format* format, + media_source* out_source, char* out_name) { - // PrepareToConnect() is the second stage of format negotiations that happens - // inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat() - // method has been called, and that node has potentially changed the proposed - // format. It may also have left wildcards in the format. PrepareToConnect() - // *must* fully specialize the format before returning! CALLED(); status_t err; - node_output *channel = FindOutput(what); + NodeOutput *channel = _FindOutput(what); // is this our output? - if (channel == NULL) - { - fprintf(stderr, "OpenSoundNode::PrepareToConnect returning B_MEDIA_BAD_SOURCE\n"); + if (channel == NULL) { + fprintf(stderr, "OpenSoundNode::PrepareToConnect returning " + "B_MEDIA_BAD_SOURCE\n"); return B_MEDIA_BAD_SOURCE; } @@ -848,23 +964,22 @@ OpenSoundNode::PrepareToConnect(const media_source& what, const media_destinatio BAutolock L(fDevice->Locker()); - OpenSoundDeviceEngine *engine = fDevice->NextFreeEngineAt(channel->fEngineId, false); - if (!engine) { + OpenSoundDeviceEngine *engine = fDevice->NextFreeEngineAt( + channel->fEngineIndex, false); + if (engine == NULL) return B_BUSY; - } // the format may not yet be fully specialized (the consumer might have // passed back some wildcards). Finish specializing it now, and return an // error if we don't support the requested format. - if (format->type != B_MEDIA_RAW_AUDIO) //XXX:NONRAW - { + if (format->type != B_MEDIA_RAW_AUDIO) { fprintf(stderr, "\tnon-raw-audio format?!\n"); return B_MEDIA_BAD_FORMAT; } - // !!! validate all other fields except for buffer_size here, because the consumer might have - // supplied different values from AcceptFormat()? - err = engine->SpecializeFormatFor(channel->fAFmt, *format, true); + // !!! validate all other fields except for buffer_size here, because the + // consumer might have supplied different values from AcceptFormat()? + err = engine->SpecializeFormatFor(channel->fOSSFormatFlags, *format, true); if (err < B_OK) return err; @@ -872,14 +987,15 @@ OpenSoundNode::PrepareToConnect(const media_source& what, const media_destinatio #if 0 // check the buffer size, which may still be wildcarded - if (format->u.raw_audio.buffer_size == media_raw_audio_format::wildcard.buffer_size) - { - format->u.raw_audio.buffer_size = 2048; // pick something comfortable to suggest - fprintf(stderr, "\tno buffer size provided, suggesting %lu\n", format->u.raw_audio.buffer_size); - } - else - { - fprintf(stderr, "\tconsumer suggested buffer_size %lu\n", format->u.raw_audio.buffer_size); + if (format->u.raw_audio.buffer_size + == media_raw_audio_format::wildcard.buffer_size) { + format->u.raw_audio.buffer_size = 2048; + // pick something comfortable to suggest + fprintf(stderr, "\tno buffer size provided, suggesting %lu\n", + format->u.raw_audio.buffer_size); + } else { + fprintf(stderr, "\tconsumer suggested buffer_size %lu\n", + format->u.raw_audio.buffer_size); } #endif @@ -891,17 +1007,20 @@ OpenSoundNode::PrepareToConnect(const media_source& what, const media_destinatio return B_OK; } + void -OpenSoundNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) +OpenSoundNode::Connect(status_t error, const media_source& source, + const media_destination& destination, const media_format& format, + char* io_name) { CALLED(); - node_output *channel = FindOutput(source); + NodeOutput *channel = _FindOutput(source); // is this our output? - if (channel == NULL) - { - fprintf(stderr, "OpenSoundNode::Connect returning (cause : B_MEDIA_BAD_SOURCE)\n"); + if (channel == NULL) { + fprintf(stderr, "OpenSoundNode::Connect returning (cause : " + "B_MEDIA_BAD_SOURCE)\n"); return; } @@ -909,11 +1028,10 @@ OpenSoundNode::Connect(status_t error, const media_source& source, const media_d if (engine == NULL) return; - // If something earlier failed, Connect() might still be called, but with a non-zero - // error code. When that happens we simply unreserve the connection and do - // nothing else. - if (error) - { + // If something earlier failed, Connect() might still be called, but with + // a non-zero error code. When that happens we simply unreserve the + // connection and do nothing else. + if (error) { channel->fOutput.destination = media_destination::null; channel->fOutput.format = channel->fPreferredFormat; engine->Close(); @@ -921,17 +1039,19 @@ OpenSoundNode::Connect(status_t error, const media_source& source, const media_d return; } - // Okay, the connection has been confirmed. Record the destination and format - // that we agreed on, and report our connection name again. + // Okay, the connection has been confirmed. Record the destination and + // format that we agreed on, and report our connection name again. channel->fOutput.destination = destination; channel->fOutput.format = format; strncpy(io_name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); // reset our buffer duration, etc. to avoid later calculations - bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000 - / ( (channel->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) - * channel->fOutput.format.u.raw_audio.channel_count) - / ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100)); + bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size + * 10000 + / ( (channel->fOutput.format.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK) + * channel->fOutput.format.u.raw_audio.channel_count) + / ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100)); SetBufferDuration(duration); @@ -942,46 +1062,48 @@ OpenSoundNode::Connect(status_t error, const media_source& source, const media_d PRINT(("\tdownstream latency = %Ld\n", fLatency)); fInternalLatency = BufferDuration(); - PRINT(("\tbuffer-filling took %Ld usec on this machine\n", fInternalLatency)); + PRINT(("\tbuffer-filling took %Ld usec on this machine\n", + fInternalLatency)); //SetEventLatency(fLatency + fInternalLatency); - // Set up the buffer group for our connection, as long as nobody handed us a - // buffer group (via SetBufferGroup()) prior to this. That can happen, for example, - // if the consumer calls SetOutputBuffersFor() on us from within its Connected() - // method. + // Set up the buffer group for our connection, as long as nobody handed us + // a buffer group (via SetBufferGroup()) prior to this. That can happen, + // for example, if the consumer calls SetOutputBuffersFor() on us from + // within its Connected() method. if (!channel->fBufferGroup) - AllocateBuffers(*channel); + _AllocateBuffers(*channel); engine->StartRecording(); // we are sure the thread is started - //StartThread(); - StartRecThread(channel); + _StartRecThread(channel); } + void -OpenSoundNode::Disconnect(const media_source& what, const media_destination& where) +OpenSoundNode::Disconnect(const media_source& what, + const media_destination& where) { CALLED(); - node_output *channel = FindOutput(what); + NodeOutput *channel = _FindOutput(what); // is this our output? - if (channel == NULL) - { - fprintf(stderr, "OpenSoundNode::Disconnect() returning (cause : B_MEDIA_BAD_SOURCE)\n"); + if (channel == NULL) { + fprintf(stderr, "OpenSoundNode::Disconnect() returning (cause : " + "B_MEDIA_BAD_SOURCE)\n"); return; } - StopRecThread(channel); + _StopRecThread(channel); BAutolock L(fDevice->Locker()); - OpenSoundDeviceEngine *engine = channel->fRealEngine; + OpenSoundDeviceEngine* engine = channel->fRealEngine; // Make sure that our connection is the one being disconnected - if ((where == channel->fOutput.destination) && (what == channel->fOutput.source)) - { + if (where == channel->fOutput.destination + && what == channel->fOutput.source) { if (engine) engine->Close(); channel->fRealEngine = NULL; @@ -989,60 +1111,57 @@ OpenSoundNode::Disconnect(const media_source& what, const media_destination& whe channel->fOutput.format = channel->fPreferredFormat; delete channel->fBufferGroup; channel->fBufferGroup = NULL; - } - else - { - fprintf(stderr, "\tDisconnect() called with wrong source/destination (%ld/%ld), ours is (%ld/%ld)\n", - what.id, where.id, channel->fOutput.source.id, channel->fOutput.destination.id); + } else { + fprintf(stderr, "\tDisconnect() called with wrong source/destination " + "(%ld/%ld), ours is (%ld/%ld)\n", what.id, where.id, + channel->fOutput.source.id, channel->fOutput.destination.id); } } + void -OpenSoundNode::LateNoticeReceived(const media_source& what, bigtime_t how_much, bigtime_t performance_time) +OpenSoundNode::LateNoticeReceived(const media_source& what, bigtime_t how_much, + bigtime_t performance_time) { CALLED(); - node_output *channel = FindOutput(what); - // is this our output? + NodeOutput *channel = _FindOutput(what); if (channel == NULL) - { return; - } - // If we're late, we need to catch up. Respond in a manner appropriate to our - // current run mode. - if (RunMode() == B_RECORDING) - { + // If we're late, we need to catch up. Respond in a manner appropriate + // to our current run mode. + if (RunMode() == B_RECORDING) { // A hardware capture node can't adjust; it simply emits buffers at // appropriate points. We (partially) simulate this by not adjusting // our behavior upon receiving late notices -- after all, the hardware // can't choose to capture "sooner".... - } - else if (RunMode() == B_INCREASE_LATENCY) - { + } else if (RunMode() == B_INCREASE_LATENCY) { // We're late, and our run mode dictates that we try to produce buffers - // earlier in order to catch up. This argues that the downstream nodes are - // not properly reporting their latency, but there's not much we can do about - // that at the moment, so we try to start producing buffers earlier to - // compensate. + // earlier in order to catch up. This argues that the downstream nodes + // are not properly reporting their latency, but there's not much we + // can do about that at the moment, so we try to start producing + // buffers earlier to compensate. fInternalLatency += how_much; SetEventLatency(fLatency + fInternalLatency); - fprintf(stderr, "\tincreasing latency to %Ld\n", fLatency + fInternalLatency); - } - else - { - // The other run modes dictate various strategies for sacrificing data quality - // in the interests of timely data delivery. The way *we* do this is to skip - // a buffer, which catches us up in time by one buffer duration. - /*size_t nSamples = fOutput.format.u.raw_audio.buffer_size / sizeof(float); - mSamplesSent += nSamples;*/ + fprintf(stderr, "\tincreasing latency to %Ld\n", + fLatency + fInternalLatency); + } else { + // The other run modes dictate various strategies for sacrificing data + // quality in the interests of timely data delivery. The way *we* do + // this is to skip a buffer, which catches us up in time by one buffer + // duration. +// size_t nSamples = fOutput.format.u.raw_audio.buffer_size +// / sizeof(float); +// mSamplesSent += nSamples; fprintf(stderr, "\tskipping a buffer to try to catch up\n"); } } + void OpenSoundNode::EnableOutput(const media_source& what, bool enabled, int32* _deprecated_) { @@ -1052,7 +1171,7 @@ OpenSoundNode::EnableOutput(const media_source& what, bool enabled, int32* _depr // which one matched the given source, and then enable/disable that one. But this // node only has one output, so I just make sure the given source matches, then set // the enable state accordingly. - node_output *channel = FindOutput(what); + NodeOutput *channel = _FindOutput(what); if (channel != NULL) { @@ -1068,16 +1187,16 @@ OpenSoundNode::AdditionalBufferRequested(const media_source& source, media_buffe return; } -// -------------------------------------------------------- // -// implementation for BMediaEventLooper -// -------------------------------------------------------- // -void OpenSoundNode::HandleEvent( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) +// #pragma mark - BMediaEventLooper + + +void +OpenSoundNode::HandleEvent(const media_timed_event* event, bigtime_t lateness, + bool realTimeEvent) { - /**/CALLED(); + CALLED(); + switch (event->type) { case BTimedEventQueue::B_START: HandleStart(event,lateness,realTimeEvent); @@ -1092,7 +1211,8 @@ void OpenSoundNode::HandleEvent( HandleStop(event,lateness,realTimeEvent); break; case BTimedEventQueue::B_HANDLE_BUFFER: - //PRINT(("HandleEvent: B_HANDLE_BUFFER, RunState= %d\n", RunState())); +// PRINT(("HandleEvent: B_HANDLE_BUFFER, RunState= %d\n", +// RunState())); if (RunState() == BMediaEventLooper::B_STARTED) { HandleBuffer(event,lateness,realTimeEvent); } @@ -1109,26 +1229,28 @@ void OpenSoundNode::HandleEvent( } } -// protected: -// how should we handle late buffers? drop them? -// notify the producer? -status_t OpenSoundNode::HandleBuffer( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) +// protected +status_t +OpenSoundNode::HandleBuffer(const media_timed_event* event, + bigtime_t lateness, bool realTimeEvent) { + // TODO: How should we handle late buffers? Drop them? + // Notify the producer? + CALLED(); - BBuffer * buffer = const_cast((BBuffer*)event->pointer); + BBuffer* buffer = const_cast((BBuffer*)event->pointer); if (buffer == 0) { fprintf(stderr,"<- B_BAD_VALUE\n"); return B_BAD_VALUE; } - node_input *channel = FindInput(buffer->Header()->destination); - //PRINT(("buffer->Header()->destination : %i\n", buffer->Header()->destination)); + NodeInput *channel = _FindInput(buffer->Header()->destination); +// PRINT(("buffer->Header()->destination : %i\n", +// buffer->Header()->destination)); - if(channel==NULL) { + if (channel == NULL) { + buffer->Recycle(); fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); return B_MEDIA_BAD_DESTINATION; } @@ -1137,45 +1259,48 @@ status_t OpenSoundNode::HandleBuffer( bigtime_t now = TimeSource()->Now(); bigtime_t perf_time = hdr->start_time; - // the how_early calculate here doesn't include scheduling latency because + // the how_early calculated here doesn't include scheduling latency because // we've already been scheduled to handle the buffer bigtime_t how_early = perf_time - EventLatency() - now; // if the buffer is late, we ignore it and report the fact to the producer // who sent it to us - if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode... - (RunMode() != B_RECORDING) && // ...or in recording mode - (how_early < 0LL) && false /* XXX:DEBUG */) - { + if (RunMode() != B_OFFLINE + // lateness doesn't matter in offline mode... + && RunMode() != B_RECORDING + // ...or in recording mode + && how_early < 0LL + && false) { + // TODO: Debug //mLateBuffers++; NotifyLateProducer(channel->fInput.source, -how_early, perf_time); fprintf(stderr," <- LATE BUFFER : %lli\n", how_early); buffer->Recycle(); - release_sem(fBufferAvailableSem); } else { - //WriteBuffer(buffer, *channel); - fDevice->Locker()->Lock(); if (channel->fBuffers.CountItems() > 10) { fDevice->Locker()->Unlock(); - PRINT(("OpenSoundNode::HandleBuffer too many buffers, recycling\n")); + PRINT(("OpenSoundNode::HandleBuffer too many buffers, " + "recycling\n")); buffer->Recycle(); - release_sem(fBufferAvailableSem); } else { - //PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); +// PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, +// how_early:%lli\n", channel->fEngineIndex, how_early)); channel->fBuffers.AddItem(buffer); fDevice->Locker()->Unlock(); - release_sem(fBufferAvailableSem); } #if 0 if (channel->fBuffer != NULL) { - PRINT(("OpenSoundNode::HandleBuffer snoozing recycling channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); + PRINT(("OpenSoundNode::HandleBuffer snoozing recycling " + "channelId : %i, how_early:%lli\n", channel->fEngineIndex, + how_early)); //channel->fBuffer->Recycle(); release_sem(fBufferAvailableSem); snooze(100); if(channel->fBuffer != NULL) { - PRINT(("OpenSoundNode::HandleBuffer old buffer still there, recycling\n")); + PRINT(("OpenSoundNode::HandleBuffer old buffer still there, " + "recycling\n")); buffer->Recycle(); //release_sem(fBufferAvailableSem); } else { @@ -1183,7 +1308,8 @@ status_t OpenSoundNode::HandleBuffer( release_sem(fBufferAvailableSem); } } else { - //PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); + //PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, " + "how_early:%lli\n", channel->fEngineIndex, how_early)); channel->fBuffer = buffer; release_sem(fBufferAvailableSem); } @@ -1192,13 +1318,16 @@ status_t OpenSoundNode::HandleBuffer( return B_OK; } -status_t OpenSoundNode::HandleDataStatus( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) + +status_t +OpenSoundNode::HandleDataStatus(const media_timed_event* event, + bigtime_t lateness, bool realTimeEvent) { - //CALLED(); - PRINT(("OpenSoundNode::HandleDataStatus status:%li, lateness:%li\n", event->data, lateness)); +// CALLED(); + + PRINT(("OpenSoundNode::HandleDataStatus status:%li, lateness:%li\n", + event->data, lateness)); + switch(event->data) { case B_DATA_NOT_AVAILABLE: break; @@ -1212,73 +1341,75 @@ status_t OpenSoundNode::HandleDataStatus( return B_OK; } -status_t OpenSoundNode::HandleStart( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) + +status_t +OpenSoundNode::HandleStart(const media_timed_event* event, bigtime_t lateness, + bool realTimeEvent) { CALLED(); if (RunState() != B_STARTED) { - + // TODO: What should happen here? } return B_OK; } -status_t OpenSoundNode::HandleSeek( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) + +status_t +OpenSoundNode::HandleSeek(const media_timed_event* event, bigtime_t lateness, + bool realTimeEvent) { CALLED(); - PRINT(("OpenSoundNode::HandleSeek(t=%lld,d=%li,bd=%lld)\n",event->event_time,event->data,event->bigdata)); + PRINT(("OpenSoundNode::HandleSeek(t=%lld, d=%li, bd=%lld)\n", + event->event_time,event->data,event->bigdata)); return B_OK; } - -status_t OpenSoundNode::HandleWarp( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) + + +status_t +OpenSoundNode::HandleWarp(const media_timed_event* event, + bigtime_t lateness, bool realTimeEvent) { CALLED(); return B_OK; } -status_t OpenSoundNode::HandleStop( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) + +status_t +OpenSoundNode::HandleStop(const media_timed_event* event, bigtime_t lateness, + bool realTimeEvent) { CALLED(); // flush the queue so downstreamers don't get any more - EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); - - //StopThread(); + EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, + BTimedEventQueue::B_HANDLE_BUFFER); + return B_OK; } -status_t OpenSoundNode::HandleParameter( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent) + +status_t +OpenSoundNode::HandleParameter(const media_timed_event* event, + bigtime_t lateness, bool realTimeEvent) { CALLED(); return B_OK; } -// -------------------------------------------------------- // -// implemention of BTimeSource -// -------------------------------------------------------- // + +// #pragma mark - BTimeSource + void OpenSoundNode::SetRunMode(run_mode mode) { CALLED(); - PRINT(("OpenSoundNode::SetRunMode mode:%i\n", mode)); + PRINT(("OpenSoundNode::SetRunMode(%d)\n", mode)); //BTimeSource::SetRunMode(mode); } + status_t -OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved) +OpenSoundNode::TimeSourceOp(const time_source_op_info& op, void* _reserved) { CALLED(); switch(op.op) { @@ -1286,7 +1417,6 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved) PRINT(("TimeSourceOp op B_TIMESOURCE_START\n")); if (RunState() != BMediaEventLooper::B_STARTED) { fTimeSourceStarted = true; - //StartThread(); media_timed_event startEvent(0, BTimedEventQueue::B_START); EventQueue()->AddEvent(startEvent); @@ -1298,7 +1428,6 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved) media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); EventQueue()->AddEvent(stopEvent); fTimeSourceStarted = false; - //StopThread(); PublishTime(0, 0, 0); } break; @@ -1308,7 +1437,6 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved) media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); EventQueue()->AddEvent(stopEvent); fTimeSourceStarted = false; - //StopThread(); PublishTime(0, 0, 0); } break; @@ -1322,29 +1450,31 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved) return B_OK; } -// -------------------------------------------------------- // -// implemention of BControllable -// -------------------------------------------------------- // + +// #pragma mark - BControllable + status_t -OpenSoundNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, size_t* ioSize) +OpenSoundNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, + size_t* ioSize) { - oss_mixext mixext; - oss_mixer_value mixval; - OpenSoundDeviceMixer *mixer = fDevice->MixerAt(0); - status_t err; - int i, chans = 1; - int sliderShift = 8; CALLED(); + + int channelCount = 1; + int sliderShift = 8; + OpenSoundDeviceMixer* mixer = fDevice->MixerAt(0); if (!mixer) return ENODEV; - + PRINT(("id : %i, *ioSize=%d\n", id, *ioSize)); - err = mixer->GetExtInfo(id, &mixext); + oss_mixext mixext; + status_t err = mixer->GetExtInfo(id, &mixext); if (err < B_OK) return err; + + oss_mixer_value mixval; mixval.ctrl = mixext.ctrl; mixval.timestamp = mixext.timestamp; @@ -1356,7 +1486,7 @@ OpenSoundNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, return EINVAL; BParameter *parameter = NULL; - for(int32 i=0; iCountParameters(); i++) { + for (int32 i = 0; i < fWeb->CountParameters(); i++) { parameter = fWeb->ParameterAt(i); if(parameter->ID() == id) break; @@ -1389,24 +1519,25 @@ OpenSoundNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, case MIXT_STEREODB: case MIXT_STEREOSLIDER16: case MIXT_STEREOSLIDER: - chans = 2; + channelCount = 2; case MIXT_SLIDER: case MIXT_MONODB: case MIXT_MONOSLIDER16: case MIXT_MONOSLIDER: - if (*ioSize < chans * sizeof(float)) + if (*ioSize < channelCount * sizeof(float)) return EINVAL; if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER) return EINVAL; if (mixext.type == MIXT_STEREOSLIDER16 || mixext.type == MIXT_MONOSLIDER16) sliderShift = 16; - *ioSize = chans * sizeof(float); + *ioSize = channelCount * sizeof(float); ((float *)value)[0] = (float)(mixval.value & ((1 << sliderShift) - 1)); PRINT(("%s: value[O] = %f\n", __FUNCTION__, ((float *)value)[0])); - if (chans < 2) + if (channelCount < 2) return B_OK; - ((float *)value)[1] = (float)((mixval.value >> sliderShift) & ((1 << sliderShift) - 1)); + ((float *)value)[1] = (float)((mixval.value >> sliderShift) + & ((1 << sliderShift) - 1)); PRINT(("%s: value[1] = %f\n", __FUNCTION__, ((float *)value)[1])); return B_OK; break; @@ -1439,102 +1570,27 @@ OpenSoundNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, case MIXT_STEREOSLIDER16: break;*/ default: - PRINT(("OpenSoundNode::%s: unknown mixer control type %d\n", __FUNCTION__, mixext.type)); + PRINT(("OpenSoundNode::%s: unknown mixer control type %d\n", + __FUNCTION__, mixext.type)); } *ioSize = 0; return EINVAL; -#if MA - BParameter *parameter = NULL; - for(int32 i=0; iCountParameters(); i++) { - parameter = fWeb->ParameterAt(i); - if(parameter->ID() == id) - break; - } - - if(!parameter) { - // Hmmm, we were asked for a parameter that we don't actually - // support. Report an error back to the caller. - PRINT(("\terror - asked for illegal parameter %ld\n", id)); - return B_ERROR; - } - - multi_mix_value_info MMVI; - multi_mix_value MMV[2]; - int rval; - MMVI.values = MMV; - id = id - 100; - MMVI.item_count = 0; - - if (*ioSize < sizeof(float)) - return B_ERROR; - - if(parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { - MMVI.item_count = 1; - MMV[0].id = id; - - if(parameter->CountChannels() == 2) { - if (*ioSize < 2*sizeof(float)) - return B_ERROR; - MMVI.item_count = 2; - MMV[1].id = id + 1; - } - - } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { - MMVI.item_count = 1; - MMV[0].id = id; - } - - if(MMVI.item_count > 0) { - rval = fDevice->DoGetMix(&MMVI); - - if (B_OK != rval) { - fprintf(stderr, "Failed on DRIVER_GET_MIX\n"); - } else { - - if(parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { - ((float*)value)[0] = MMV[0].gain; - *ioSize = sizeof(float); - - if(parameter->CountChannels() == 2) { - ((float*)value)[1] = MMV[1].gain; - *ioSize = 2*sizeof(float); - } - - for(uint32 i=0; i < (*ioSize/sizeof(float)); i++) { - PRINT(("B_CONTINUOUS_PARAMETER value[%i] : %f\n", i, ((float*)value)[i])); - } - } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { - - BDiscreteParameter *dparameter = (BDiscreteParameter*) parameter; - if(dparameter->CountItems()<=2) { - ((int32*)value)[0] = (MMV[0].enable) ? 1 : 0; - } else { - ((int32*)value)[0] = MMV[0].mux; - } - *ioSize = sizeof(int32); - - for(uint32 i=0; i < (*ioSize/sizeof(int32)); i++) { - PRINT(("B_DISCRETE_PARAMETER value[%i] : %i\n", i, ((int32*)value)[i])); - } - } - - } - } - return B_OK; -#endif } + void -OpenSoundNode::SetParameterValue(int32 id, bigtime_t performance_time, const void* value, size_t size) +OpenSoundNode::SetParameterValue(int32 id, bigtime_t performance_time, + const void* value, size_t size) { oss_mixext mixext; oss_mixer_value mixval; OpenSoundDeviceMixer *mixer = fDevice->MixerAt(0); status_t err; - int i, chans = 1; + int i, channelCount = 1; int sliderShift = 8; CALLED(); - PRINT(("id : %i, performance_time : %lld, size : %i\n", id, performance_time, size)); + PRINT(("id : %i, performance_time : %lld, size : %i\n", id, + performance_time, size)); if (!mixer) return; @@ -1579,7 +1635,7 @@ OpenSoundNode::SetParameterValue(int32 id, bigtime_t performance_time, const voi // So we have to let users know about it. // XXX: find something better, doesn't work correctly here. // XXX: try a timed event ? - PropagateParameterChanges(mixext.ctrl, mixext.type, mixext.id); + _PropagateParameterChanges(mixext.ctrl, mixext.type, mixext.id); return; case MIXT_ENUM: @@ -1591,12 +1647,12 @@ OpenSoundNode::SetParameterValue(int32 id, bigtime_t performance_time, const voi case MIXT_STEREODB: case MIXT_STEREOSLIDER16: case MIXT_STEREOSLIDER: - chans = 2; + channelCount = 2; case MIXT_SLIDER: case MIXT_MONODB: case MIXT_MONOSLIDER16: case MIXT_MONOSLIDER: - if (size < chans * sizeof(float)) + if (size < channelCount * sizeof(float)) return; if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER) return; @@ -1604,11 +1660,17 @@ OpenSoundNode::SetParameterValue(int32 id, bigtime_t performance_time, const voi mixext.type == MIXT_MONOSLIDER16) sliderShift = 16; mixval.value = 0; - PRINT(("-------- sliderShift=%d, v = %08x, v & %08x = %08x\n", sliderShift, mixval.value, ((1 << sliderShift) - 1), mixval.value & ((1 << sliderShift) - 1))); + + PRINT(("-------- sliderShift=%d, v = %08x, v & %08x = %08x\n", + sliderShift, mixval.value, ((1 << sliderShift) - 1), + mixval.value & ((1 << sliderShift) - 1))); + mixval.value |= ((int)(((float *)value)[0])) & ((1 << sliderShift) - 1); - if (chans > 1) { - mixval.value |= (((int)(((float *)value)[1])) & ((1 << sliderShift) - 1)) << sliderShift; + if (channelCount > 1) { + mixval.value |= (((int)(((float *)value)[1])) + & ((1 << sliderShift) - 1)) << sliderShift; } + PRINT(("%s: value = 0x%08x\n", __FUNCTION__, mixval.value)); mixer->SetMixerValue(&mixval); return; @@ -1631,163 +1693,113 @@ OpenSoundNode::SetParameterValue(int32 id, bigtime_t performance_time, const voi break; case MIXT_HEXVALUE: break; -/* case MIXT_MONODB: - break; - case MIXT_STEREODB: - break;*/ +// case MIXT_MONODB: +// break; +// case MIXT_STEREODB: +// break; case MIXT_3D: break; -/* case MIXT_MONOSLIDER16: - break; - case MIXT_STEREOSLIDER16: - break;*/ +// case MIXT_MONOSLIDER16: +// break; +// case MIXT_STEREOSLIDER16: +// break; default: - PRINT(("OpenSoundNode::%s: unknown mixer control type %d\n", __FUNCTION__, mixext.type)); + PRINT(("OpenSoundNode::%s: unknown mixer control type %d\n", + __FUNCTION__, mixext.type)); } return; -#if MA - BParameter *parameter = NULL; - for(int32 i=0; iCountParameters(); i++) { - parameter = fWeb->ParameterAt(i); - if(parameter->ID() == id) - break; - } - if(parameter) { - multi_mix_value_info MMVI; - multi_mix_value MMV[2]; - int rval; - MMVI.values = MMV; - id = id - 100; - MMVI.item_count = 0; - - if(parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { - for(uint32 i=0; i < (size/sizeof(float)); i++) { - PRINT(("B_CONTINUOUS_PARAMETER value[%i] : %f\n", i, ((float*)value)[i])); - } - MMVI.item_count = 1; - MMV[0].id = id; - MMV[0].gain = ((float*)value)[0]; - - if(parameter->CountChannels() == 2) { - MMVI.item_count = 2; - MMV[1].id = id + 1; - MMV[1].gain = ((float*)value)[1]; - } - - } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { - for(uint32 i=0; i < (size/sizeof(int32)); i++) { - PRINT(("B_DISCRETE_PARAMETER value[%i] : %i\n", i, ((int32*)value)[i])); - } - BDiscreteParameter *dparameter = (BDiscreteParameter*) parameter; - - if(dparameter->CountItems()<=2) { - MMVI.item_count = 1; - MMV[0].id = id; - MMV[0].enable = (((int32*)value)[0] == 1) ? true : false; - } else { - MMVI.item_count = 1; - MMV[0].id = id; - MMV[0].mux = ((uint32*)value)[0]; - } - } - - if(MMVI.item_count > 0) { - rval = fDevice->DoSetMix(&MMVI); - - if (B_OK != rval) - { - fprintf(stderr, "Failed on DRIVER_SET_MIX\n"); - } - } - } - -#endif } + BParameterWeb* OpenSoundNode::MakeParameterWeb() { CALLED(); BParameterWeb* web = new BParameterWeb; - OpenSoundDeviceMixer *mixer = fDevice->MixerAt(0); - oss_mixext mixext; - int i, mixext_count; - // XXX: TODO: the card might change the mixer controls at some point, + // TODO: the card might change the mixer controls at some point, // we should detect it (poll) and recreate the parameter web and // re-set it. // TODO: cache mixext[...] and poll for changes in their update_counter. - // some cards don't have a mixer, just put a placeholder then - if (!mixer) { - BParameterGroup *child = web->MakeGroup("No mixer"); - child->MakeNullParameter(1, B_MEDIA_UNKNOWN_TYPE, "No Mixer", B_GENERIC); + OpenSoundDeviceMixer* mixer = fDevice->MixerAt(0); + if (mixer == NULL) { + // some cards don't have a mixer, just put a placeholder then + BParameterGroup* child = web->MakeGroup("No mixer"); + child->MakeNullParameter(1, B_MEDIA_UNKNOWN_TYPE, "No Mixer", + B_GENERIC); return web; } - // - mixext_count = mixer->CountExtInfos(); + int mixext_count = mixer->CountExtInfos(); PRINT(("OpenSoundNode::MakeParameterWeb %i ExtInfos\n", mixext_count)); - for(i = 0; i < mixext_count; i++) { + for (int32 i = 0; i < mixext_count; i++) { + oss_mixext mixext; if (mixer->GetExtInfo(i, &mixext) < B_OK) continue; if (mixext.type == MIXT_DEVROOT) { - oss_mixext_root *extroot = (oss_mixext_root *)mixext.data; - PRINT(("OpenSoundNode: mixext[%d]: ROOT\n", i)); - int32 nb = 0; - const char* childName = mixext.extname; - childName = extroot->id;//extroot->name; - BParameterGroup *child = web->MakeGroup(childName); - ProcessGroup(child, i, nb); + oss_mixext_root* extroot = (oss_mixext_root*)mixext.data; + PRINT(("OpenSoundNode: mixext[%d]: ROOT\n", i)); + int32 nb = 0; + const char* childName = mixext.extname; + childName = extroot->id; // extroot->name; + BParameterGroup *child = web->MakeGroup(childName); + _ProcessGroup(child, i, nb); } } return web; } + +// #pragma mark - OpenSoundNode specific + + void -OpenSoundNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParameters) +OpenSoundNode::_ProcessGroup(BParameterGroup *group, int32 index, + int32& nbParameters) { CALLED(); - OpenSoundDeviceMixer *mixer = fDevice->MixerAt(0); - oss_mixext mixext; - int i, mixext_count; + // TODO: It looks wrong to use the same mixer in a recursive function! + OpenSoundDeviceMixer* mixer = fDevice->MixerAt(0); - mixext_count = mixer->CountExtInfos(); - - for(i = 0; i < mixext_count; i++) { + int mixext_count = mixer->CountExtInfos(); + for (int32 i = 0; i < mixext_count; i++) { + oss_mixext mixext; if (mixer->GetExtInfo(i, &mixext) < B_OK) continue; // only keep direct children of that group if (mixext.parent != index) continue; - const char *childName = mixext.extname; - const char *sliderUnit = "";//"(linear)"; - const char *continuousKind = B_GAIN; - int32 nb = 1; - BParameterGroup *child; - - PRINT(("OpenSoundNode: mixext[%d]: { %s/%s, type=%d, parent=%d, min=%d, max=%d, flags=0x%08x, control_no=%d, desc=%d, update_counter=%d }\n", - i, (mixext.type != MIXT_MARKER)?mixext.id:"", - (mixext.type != MIXT_MARKER)?mixext.extname:"", - mixext.type, mixext.parent, - mixext.minvalue, mixext.maxvalue, - mixext.flags, mixext.control_no, + + PRINT(("OpenSoundNode: mixext[%d]: { %s/%s, type=%d, parent=%d, " + "min=%d, max=%d, flags=0x%08x, control_no=%d, desc=%d, " + "update_counter=%d }\n", i, + (mixext.type != MIXT_MARKER) ? mixext.id : "", + (mixext.type != MIXT_MARKER) ? mixext.extname : "", + mixext.type, mixext.parent, + mixext.minvalue, mixext.maxvalue, + mixext.flags, mixext.control_no, mixext.desc, mixext.update_counter)); // should actually rename the whole group but it's too late there. + const char *childName = mixext.extname; if (mixext.flags & MIXF_MAINVOL) childName = "Master Gain"; + const char *sliderUnit = "";//"(linear)"; if (mixext.flags & MIXF_HZ) sliderUnit = "Hz"; + const char *continuousKind = B_GAIN; + BParameterGroup* child; + switch (mixext.type) { case MIXT_DEVROOT: // root item, should be done already @@ -1795,18 +1807,23 @@ OpenSoundNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParame case MIXT_GROUP: PRINT(("OpenSoundNode: mixext[%d]: GROUP\n", i)); child = group->MakeGroup(childName); - child->MakeNullParameter(i, B_MEDIA_RAW_AUDIO, childName, B_WEB_BUFFER_OUTPUT); - ProcessGroup(child, i, nb); + child->MakeNullParameter(i, B_MEDIA_RAW_AUDIO, childName, + B_WEB_BUFFER_OUTPUT); + _ProcessGroup(child, i, nb); break; case MIXT_ONOFF: PRINT(("OpenSoundNode: mixext[%d]: ONOFF\n", i)); // multiaudio node adds 100 to IDs !? - if(0/*MMC[i].string == S_MUTE*/) - group->MakeDiscreteParameter(i, B_MEDIA_RAW_AUDIO, childName, B_MUTE); - else - group->MakeDiscreteParameter(i, B_MEDIA_RAW_AUDIO, childName, B_ENABLE); - if(nbParameters>0) { - (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); + if (0/*MMC[i].string == S_MUTE*/) { + group->MakeDiscreteParameter(i, B_MEDIA_RAW_AUDIO, childName, + B_MUTE); + } else { + group->MakeDiscreteParameter(i, B_MEDIA_RAW_AUDIO, childName, + B_ENABLE); + } + if (nbParameters > 0) { + (group->ParameterAt(nbParameters - 1))->AddOutput( + group->ParameterAt(nbParameters)); nbParameters++; } break; @@ -1814,14 +1831,16 @@ OpenSoundNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParame { PRINT(("OpenSoundNode: mixext[%d]: ENUM\n", i)); BDiscreteParameter *parameter = - group->MakeDiscreteParameter(i, B_MEDIA_RAW_AUDIO, childName, B_INPUT_MUX); - if(nbParameters>0) { - (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); + group->MakeDiscreteParameter(i, B_MEDIA_RAW_AUDIO, childName, + B_INPUT_MUX); + if (nbParameters > 0) { + (group->ParameterAt(nbParameters - 1))->AddOutput( + group->ParameterAt(nbParameters)); nbParameters++; } - ProcessMux(parameter, i); - } + _ProcessMux(parameter, i); break; + } case MIXT_MONODB: case MIXT_STEREODB: sliderUnit = "dB"; @@ -1843,8 +1862,9 @@ OpenSoundNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParame if (mixext.flags & MIXF_DECIBEL) true;//step size - group->MakeContinuousParameter(i, B_MEDIA_RAW_AUDIO, childName, continuousKind, - sliderUnit, mixext.minvalue, mixext.maxvalue, /*MMC[i].gain.granularity*/1); + group->MakeContinuousParameter(i, B_MEDIA_RAW_AUDIO, childName, + continuousKind, sliderUnit, mixext.minvalue, mixext.maxvalue, + /*TODO: should be "granularity"*/1); if (mixext.type == MIXT_STEREOSLIDER || mixext.type == MIXT_STEREOSLIDER16 || @@ -1853,7 +1873,8 @@ OpenSoundNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParame PRINT(("nb parameters : %d\n", nbParameters)); if (nbParameters > 0) { - (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); + (group->ParameterAt(nbParameters - 1))->AddOutput( + group->ParameterAt(nbParameters)); nbParameters++; } @@ -1876,94 +1897,38 @@ OpenSoundNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParame break; case MIXT_HEXVALUE: break; -/* case MIXT_MONODB: - PRINT(("OpenSoundNode::ProcessGroup: Skipping obsolete MIXT_MONODB\n")); - break; - case MIXT_STEREODB: - PRINT(("OpenSoundNode::ProcessGroup: Skipping obsolete MIXT_STEREODB\n")); - break;*/ -/* case MIXT_SLIDER: - break;*/ +// case MIXT_MONODB: +// PRINT(("OpenSoundNode::_ProcessGroup: Skipping obsolete " +// "MIXT_MONODB\n")); +// break; +// case MIXT_STEREODB: +// PRINT(("OpenSoundNode::_ProcessGroup: Skipping obsolete " +// "MIXT_STEREODB\n")); +// break; +// case MIXT_SLIDER: +// break; case MIXT_3D: break; -/* case MIXT_MONOSLIDER16: - break; - case MIXT_STEREOSLIDER16: - break;*/ +// case MIXT_MONOSLIDER16: +// break; +// case MIXT_STEREOSLIDER16: +// break; default: - PRINT(("OpenSoundNode::ProcessGroup: unknown mixer control type %d\n", mixext.type)); + PRINT(("OpenSoundNode::_ProcessGroup: unknown mixer control " + "type %d\n", mixext.type)); } } -#if MA - multi_mix_control *parent = &fDevice->MMCI.controls[index]; - multi_mix_control *MMC = fDevice->MMCI.controls; - for(int32 i=0; iMMCI.control_count; i++) { - if(MMC[i].parent != parent->id) - continue; - - const char* childName; - if(MMC[i].string != S_null) - childName = multi_string[MMC[i].string]; - else - childName = MMC[i].name; - - if(MMC[i].flags & B_MULTI_MIX_GROUP) { - PRINT(("NEW_GROUP\n")); - int32 nb = 1; - BParameterGroup *child = group->MakeGroup(childName); - child->MakeNullParameter(MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_WEB_BUFFER_OUTPUT); - ProcessGroup(child, i, nb); - } else if(MMC[i].flags & B_MULTI_MIX_MUX) { - PRINT(("NEW_MUX\n")); - BDiscreteParameter *parameter = - group->MakeDiscreteParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_INPUT_MUX); - if(nbParameters>0) { - (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); - nbParameters++; - } - ProcessMux(parameter, i); - } else if(MMC[i].flags & B_MULTI_MIX_GAIN) { - PRINT(("NEW_GAIN\n")); - group->MakeContinuousParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, "", B_MASTER_GAIN, - "dB", MMC[i].gain.min_gain, MMC[i].gain.max_gain, MMC[i].gain.granularity); - - if(i+1 MMCI.control_count && MMC[i+1].master == MMC[i].id && MMC[i+1].flags & B_MULTI_MIX_GAIN) { - group->ParameterAt(nbParameters)->SetChannelCount( - group->ParameterAt(nbParameters)->CountChannels() + 1); - i++; - } - - PRINT(("nb parameters : %d\n", nbParameters)); - if (nbParameters > 0) { - (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); - nbParameters++; - } - } else if(MMC[i].flags & B_MULTI_MIX_ENABLE) { - PRINT(("NEW_ENABLE\n")); - if(MMC[i].string == S_MUTE) - group->MakeDiscreteParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_MUTE); - else - group->MakeDiscreteParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_ENABLE); - if(nbParameters>0) { - (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); - nbParameters++; - } - } - } -#endif } + void -OpenSoundNode::ProcessMux(BDiscreteParameter *parameter, int32 index) +OpenSoundNode::_ProcessMux(BDiscreteParameter* parameter, int32 index) { CALLED(); OpenSoundDeviceMixer *mixer = fDevice->MixerAt(0); oss_mixer_enuminfo enuminfo; - status_t err; - int i; - - err = mixer->GetEnumInfo(index, &enuminfo); + status_t err = mixer->GetEnumInfo(index, &enuminfo); if (err < B_OK) { // maybe there is no list. // generate a count form 0 @@ -1971,7 +1936,7 @@ OpenSoundNode::ProcessMux(BDiscreteParameter *parameter, int32 index) if (mixer->GetExtInfo(index, &mixext) < B_OK) return; - for (i = 0; i < mixext.maxvalue; i++) { + for (int32 i = 0; i < mixext.maxvalue; i++) { BString s; s << i; parameter->AddItem(i, s.String()); @@ -1979,36 +1944,15 @@ OpenSoundNode::ProcessMux(BDiscreteParameter *parameter, int32 index) return; } - for (i = 0; i < enuminfo.nvalues; i++) { + for (int32 i = 0; i < enuminfo.nvalues; i++) { parameter->AddItem(i, &enuminfo.strings[enuminfo.strindex[i]]); } return; - -#if MA - multi_mix_control *parent = &fDevice->MMCI.controls[index]; - multi_mix_control *MMC = fDevice->MMCI.controls; - int32 itemIndex = 0; - for(int32 i=0; iMMCI.control_count; i++) { - if(MMC[i].parent != parent->id) - continue; - - const char* childName; - if(MMC[i].string != S_null) - childName = multi_string[MMC[i].string]; - else - childName = MMC[i].name; - - if(MMC[i].flags & B_MULTI_MIX_MUX_VALUE) { - PRINT(("NEW_MUX_VALUE\n")); - parameter->AddItem(itemIndex, childName); - itemIndex++; - } - } -#endif } + status_t -OpenSoundNode::PropagateParameterChanges(int from, int type, const char *id) +OpenSoundNode::_PropagateParameterChanges(int from, int type, const char* id) { oss_mixext mixext; oss_mixer_value mixval; @@ -2022,13 +1966,13 @@ OpenSoundNode::PropagateParameterChanges(int from, int type, const char *id) if (!mixer) return ENODEV; - // XXX !!! - // Cortex doesn't like that! - // try timed event - // try checking update_counter+caching - return B_OK; +// TODO: Cortex doesn't like that! +// try timed event +// try checking update_counter+caching +return B_OK; - PRINT(("OpenSoundNode::%s: from %i, type %i, id %s\n", __FUNCTION__, from, type, id)); + PRINT(("OpenSoundNode::%s: from %i, type %i, id %s\n", __FUNCTION__, from, + type, id)); for (i = 0; i < mixer->CountExtInfos(); i++) { err = mixer->GetExtInfo(i, &mixext); @@ -2050,429 +1994,152 @@ OpenSoundNode::PropagateParameterChanges(int from, int type, const char *id) if (id && strncmp(mixext.id, id, 16)) continue; - /* - BParameter *parameter = NULL; - for(int32 i=0; iCountParameters(); i++) { - parameter = fWeb->ParameterAt(i); - if(parameter->ID() == mixext.ctrl) - break; - } - - if (!parameter) - continue; - */ +// BParameter *parameter = NULL; +// for(int32 i=0; iCountParameters(); i++) { +// parameter = fWeb->ParameterAt(i); +// if(parameter->ID() == mixext.ctrl) +// break; +// } +// +// if (!parameter) +// continue; oldValuesSize = 128; newValuesSize = 128; bigtime_t last; -// PRINT(("OpenSoundNode::%s: comparing mixer control %d\n", __FUNCTION__, mixext.ctrl)); +// PRINT(("OpenSoundNode::%s: comparing mixer control %d\n", +// __FUNCTION__, mixext.ctrl)); // if (parameter->GetValue(oldValues, &oldValuesSize, &last) < B_OK) // continue; - if (GetParameterValue(mixext.ctrl, &last, newValues, &newValuesSize) < B_OK) + if (GetParameterValue(mixext.ctrl, &last, newValues, + &newValuesSize) < B_OK) { continue; -// if (oldValuesSize != newValuesSize || memcmp(oldValues, newValues, MIN(oldValuesSize, newValuesSize))) { - PRINT(("OpenSoundNode::%s: updating mixer control %d\n", __FUNCTION__, mixext.ctrl)); - BroadcastNewParameterValue(last, mixext.ctrl, newValues, newValuesSize); + } +// if (oldValuesSize != newValuesSize || memcmp(oldValues, newValues, +// MIN(oldValuesSize, newValuesSize))) { + PRINT(("OpenSoundNode::%s: updating mixer control %d\n", + __FUNCTION__, mixext.ctrl)); + BroadcastNewParameterValue(last, mixext.ctrl, newValues, + newValuesSize); // BroadcastChangedParameter(mixext.ctrl); // } } return B_OK; } -// -------------------------------------------------------- // -// OpenSoundNode specific functions -// -------------------------------------------------------- // - -#if 0 -int32 -OpenSoundNode::RunThread() -{ - int32 i; - int32 bufferAvailReq = 1; - bigtime_t timeout = MIN_SNOOZING; - CALLED(); - //set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG - - return 0; //XXX: REMOVE - - while ( 1 ) { - status_t err; - bigtime_t before = system_time(); - - // XXX: use select() here when it gets implemented! - - if (bufferAvailReq < 1) - bufferAvailReq = 1; - - PRINT(("OpenSoundNode::RunThread: waiting for %d buffers, timeout %lld\n", bufferAvailReq, timeout)); - - //acquire buffer if any - err = acquire_sem_etc( fBufferAvailableSem, bufferAvailReq, B_RELATIVE_TIMEOUT, timeout ); - if (err == B_BAD_SEM_ID ) { - return B_OK; - } - if (err == B_OK) - bufferAvailReq = 0;//1; - if (err == B_TIMED_OUT) { - PRINT(("OpenSoundNode::RunThread: acquire_sem timed out\n")); - bufferAvailReq = 0;//1; - } else { - PRINT(("OpenSoundNode::RunThread: acquire_sem done, waited %Ld\n", system_time() - before)); - } - timeout = MIN_SNOOZING; - - //PRINT(("OpenSoundNode::RunThread: RunState= %d, EventQ: %d events\n", RunState(), EventQueue()->EventCount())); - - fDevice->Locker()->Lock(); - - node_input *input = NULL; - - for(i=0; ifRealEngine; - // skip unconnected or non-busy engines - if (!engine || !engine->InUse()) - continue; - if (input->fInput.source == media_source::null - && input->fChannelId == 0) - continue; - // must be open for write - ASSERT (engine->OpenMode() & OPEN_WRITE); - - audio_buf_info abinfo; - size_t avail = engine->GetOSpace(&abinfo); - //PRINT(("OpenSoundNode::RunThread: avail: %d\n", avail)); - if (avail < 1) - continue; - -//engine->GetOUnderruns(); -#if 1 - // update the timesource - if(input->fChannelId==0) { - //PRINT(("updating timesource\n")); - UpdateTimeSource(&abinfo, *input); - } -#endif - - if(input->fBuffer!=NULL) { - if (avail < input->fBuffer->SizeUsed()) - continue; - PRINT(("OpenSoundNode::RunThread: input[%d]: sending buffer (%d bytes)\n", i, input->fBuffer->SizeUsed())); - - { - bigtime_t tout; // = input->fBuffer->SizeUsed(); - tout = abinfo.fragsize * abinfo.fragstotal - abinfo.bytes; - tout = tout * 1000000LL / (input->fInput.format.u.raw_audio.channel_count - * (input->fInput.format.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK) - * input->fInput.format.u.raw_audio.frame_rate); - if (tout && (tout < timeout)) { - //PRINT(("new timeout: %Ld\n", tout)); - timeout = tout; - } - // let's try this... - //SendLatencyChange(input->fInput.source, input->fInput.destination, EventLatency()+tout); - } - FillNextBuffer(*input, input->fBuffer); - input->fBuffer->Recycle(); - input->fBuffer = NULL; - bufferAvailReq++; - } else { - if (avail < abinfo.fragsize) - continue; - //XXX: write silence - // write a nulled fragment - PRINT(("OpenSoundNode::RunThread: input[%d]: sending zeros\n", i)); -//#ifdef WRITE_ZEROS - if(input->fInput.source != media_source::null) - WriteZeros(*input, abinfo.fragsize); -//#endif - - } - -#if 0 - // update the timesource - if(input->fChannelId==0) { - //PRINT(("updating timesource\n")); - UpdateTimeSource(&abinfo, *input); - } -#endif - - } - node_output *output = NULL; - for(i=0; ifRealEngine; - - // skip unconnected or non-busy engines - if (!engine || !engine->InUse()) - continue; - // must be open for read - ASSERT (engine->OpenMode() & OPEN_READ); -#ifdef ENABLE_REC - // make sure we're both started *and* connected before delivering a buffer - if ((RunState() != BMediaEventLooper::B_STARTED) || (output->fOutput.destination == media_destination::null)) - continue; - - audio_buf_info abinfo; - size_t avail = engine->GetISpace(&abinfo); - //PRINT(("OpenSoundNode::RunThread: I avail: %d\n", avail)); - // skip if less than 1 buffer - if (avail < output->fOutput.format.u.raw_audio.buffer_size) - continue; - - //XXX: WRITEME! - // Get the next buffer of data - BBuffer* buffer = FillNextBuffer(&abinfo, *output); - if (buffer) - { - // send the buffer downstream if and only if output is enabled - status_t err = B_ERROR; - if (output->fOutputEnabled) - err = SendBuffer(buffer, output->fOutput.destination); - //PRINT(("OpenSoundNode::RunThread: I avail: %d, OE %d, %s\n", avail, output->fOutputEnabled, strerror(err))); - if (err) { - buffer->Recycle(); - } else { - // track how much media we've delivered so far - size_t nSamples = output->fOutput.format.u.raw_audio.buffer_size - / (output->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); - output->fSamplesSent += nSamples; - //PRINT(("OpenSoundNode::%s: sent %d samples\n", __FUNCTION__, nSamples)); - } - } -#endif - } - - fDevice->Locker()->Unlock(); - - //XXX - //snooze(1000); - //release_sem(fBufferAvailableSem);//XXX - } -#if MA - multi_buffer_info MBI;//, oldMBI; - MBI.info_size = sizeof(MBI); - MBI._reserved_0 = 0; - MBI._reserved_1 = 2; - - while ( 1 ) { - //acquire buffer if any - if ( acquire_sem_etc( fBufferAvailableSem, 1, B_RELATIVE_TIMEOUT, 0 ) == B_BAD_SEM_ID ) { - return B_OK; - } - - //oldMBI = MBI; - - //send buffer - fDevice->DoBufferExchange(&MBI); - - //PRINT(("OpenSoundNode::RunThread: buffer exchanged\n")); - //PRINT(("OpenSoundNode::RunThread: played_real_time : %i\n", MBI.played_real_time)); - //PRINT(("OpenSoundNode::RunThread: played_frames_count : %i\n", MBI.played_frames_count)); - //PRINT(("OpenSoundNode::RunThread: buffer_cycle : %i\n", MBI.playback_buffer_cycle)); - - node_input *input = NULL; - - for(int32 i=0; ifChannelId) - && (input->fOldMBI.playback_buffer_cycle != MBI.playback_buffer_cycle - || fDevice->MBL.return_playback_buffers == 1) - && (input->fInput.source != media_source::null - || input->fChannelId == 0)) { - - //PRINT(("playback_buffer_cycle ok input : %i %d\n", i, MBI.playback_buffer_cycle)); - - input->fBufferCycle = (MBI.playback_buffer_cycle - 1 - + fDevice->MBL.return_playback_buffers) % fDevice->MBL.return_playback_buffers; - - // update the timesource - if(input->fChannelId==0) { - //PRINT(("updating timesource\n")); - UpdateTimeSource(MBI, input->fOldMBI, *input); - } - - input->fOldMBI = MBI; - - if(input->fBuffer!=NULL) { - /*memcpy( fDevice->MBL.playback_buffers[input->fBufferCycle][input->fChannelId].base, - input->fBuffer->Data(), input->fBuffer->SizeUsed() );*/ - FillNextBuffer(*input, input->fBuffer); - input->fBuffer->Recycle(); - input->fBuffer = NULL; - } else { - // put zeros in current buffer - if(input->fInput.source != media_source::null) - WriteZeros(*input, input->fBufferCycle); - //PRINT(("OpenSoundNode::Runthread WriteZeros\n")); - } - - //mark buffer free - release_sem( fBufferAvailableSem ); - } else { - //PRINT(("playback_buffer_cycle non ok input : %i\n", i)); - } - } - - node_output *output = NULL; - for(int32 i=0; ifOutput.destination != media_destination::null)) { - if((MBI._reserved_1 == output->fChannelId) - && (output->fOldMBI.record_buffer_cycle != MBI.record_buffer_cycle - || fDevice->MBL.return_record_buffers == 1)) { - //PRINT(("record_buffer_cycle ok\n")); - - // Get the next buffer of data - BBuffer* buffer = FillNextBuffer(MBI, *output); - if (buffer) - { - // send the buffer downstream if and only if output is enabled - status_t err = B_ERROR; - if (output->fOutputEnabled) - err = SendBuffer(buffer, output->fOutput.destination); - if (err) { - buffer->Recycle(); - } else { - // track how much media we've delivered so far - size_t nSamples = output->fOutput.format.u.raw_audio.buffer_size - / output->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; - output->fSamplesSent += nSamples; - } - } - - output->fOldMBI = MBI; - } else { - //PRINT(("record_buffer_cycle non ok\n")); - } - } - } - - } - -#endif - return B_OK; -} -#endif - int32 -OpenSoundNode::EnginePlayThread(node_input *input) +OpenSoundNode::_PlayThread(NodeInput* input) { //int32 i; CALLED(); - //set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG - signal(SIGUSR1, &_sig_handler_); + //set_thread_priority(find_thread(NULL), 5);// TODO:DEBUG + signal(SIGUSR1, &_SignalHandler); - OpenSoundDeviceEngine *engine = input->fRealEngine; + OpenSoundDeviceEngine* engine = input->fRealEngine; if (!engine || !engine->InUse()) return B_NO_INIT; // skip unconnected or non-busy engines if (input->fInput.source == media_source::null - && input->fChannelId == 0) + && input->fEngineIndex == 0) return B_NO_INIT; // must be open for write - ASSERT (engine->OpenMode() & OPEN_WRITE); + ASSERT(engine->OpenMode() & OPEN_WRITE); do { fDevice->Locker()->Lock(); audio_buf_info abinfo; size_t avail = engine->GetOSpace(&abinfo); - //PRINT(("OpenSoundNode::EnginePlayThread: avail: %d\n", avail)); + //PRINT(("OpenSoundNode::_PlayThread: avail: %d\n", avail)); #if 1 // TODO: do not assume channel 0 will always be running! // update the timesource - if(input->fChannelId==0) { + if (input->fEngineIndex == 0) { //PRINT(("updating timesource\n")); - UpdateTimeSource(&abinfo, *input); + _UpdateTimeSource(&abinfo, *input); } #endif -#if 0 - BBuffer *buffer = input->fBuffer; - input->fBuffer = NULL; -#endif - BBuffer *buffer = (BBuffer *)input->fBuffers.RemoveItem((int32)0); + BBuffer* buffer = (BBuffer*)input->fBuffers.RemoveItem(0L); fDevice->Locker()->Unlock(); if (input->fThread < 0) break; if (buffer != NULL) { - //if (avail < input->fBuffer->SizeUsed()) - // continue; - //PRINT(("OpenSoundNode::EnginePlayThread: input[%d]: sending buffer (%d bytes)\n", input->fChannelId, buffer->SizeUsed())); +// if (avail < input->fBuffer->SizeUsed()) +// continue; +// PRINT(("OpenSoundNode::_PlayThread: input[%d]: sending buffer " +// "(%d bytes)\n", input->fEngineIndex, buffer->SizeUsed())); #if 0 { bigtime_t tout; // = input->fBuffer->SizeUsed(); tout = abinfo.fragsize * abinfo.fragstotal - abinfo.bytes; - tout = tout * 1000000LL / (input->fInput.format.u.raw_audio.channel_count - * (input->fInput.format.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK) - * input->fInput.format.u.raw_audio.frame_rate); + tout = tout * 1000000LL + / (input->fInput.format.u.raw_audio.channel_count + * (input->fInput.format.AudioFormat() + & media_raw_audio_format::B_AUDIO_SIZE_MASK) + * input->fInput.format.u.raw_audio.frame_rate); if (tout && (tout < timeout)) { //PRINT(("new timeout: %Ld\n", tout)); timeout = tout; } // let's try this... - //SendLatencyChange(input->fInput.source, input->fInput.destination, EventLatency()+tout); +// SendLatencyChange(input->fInput.source, +// input->fInput.destination, EventLatency()+tout); } #endif - FillNextBuffer(*input, buffer); + input->FillBuffer(buffer); buffer->Recycle(); } else { - //if (avail < abinfo.fragsize) - // continue; - //XXX: write silence - // write a nulled fragment - //PRINT(("OpenSoundNode::EnginePlayThread: input[%d]: sending zeros\n", input->fChannelId)); +// if (avail < abinfo.fragsize) +// continue; +// TODO: write silence +// write a nulled fragment +// PRINT(("OpenSoundNode::_PlayThread: input[%d]: sending zeros\n", +// input->fEngineIndex)); //#ifdef WRITE_ZEROS if (input->fInput.source != media_source::null) - WriteZeros(*input, abinfo.fragsize); + input->WriteSilence(abinfo.fragsize); //#endif } -#if 0 - // update the timesource - if(input->fChannelId==0) { - //PRINT(("updating timesource\n")); - UpdateTimeSource(&abinfo, *input); - } -#endif } while (input->fThread > -1); + return 0; } int32 -OpenSoundNode::EngineRecThread(node_output *output) +OpenSoundNode::_RecThread(NodeOutput* output) { int32 i; CALLED(); - //set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG - signal(SIGUSR1, &_sig_handler_); + //set_thread_priority(find_thread(NULL), 5);// TODO:DEBUG + signal(SIGUSR1, &_SignalHandler); OpenSoundDeviceEngine *engine = output->fRealEngine; if (!engine || !engine->InUse()) return B_NO_INIT; - // make sure we're both started *and* connected before delivering a buffer - if ((RunState() != BMediaEventLooper::B_STARTED) || (output->fOutput.destination == media_destination::null)) + // make sure we're both started *and* connected before delivering a buffer + if ((RunState() != BMediaEventLooper::B_STARTED) + || (output->fOutput.destination == media_destination::null)) { return B_NO_INIT; + } // must be open for read - ASSERT (engine->OpenMode() & OPEN_READ); + ASSERT(engine->OpenMode() & OPEN_READ); + #ifdef ENABLE_REC fDevice->Locker()->Lock(); do { audio_buf_info abinfo; size_t avail = engine->GetISpace(&abinfo); - //PRINT(("OpenSoundNode::RunThread: I avail: %d\n", avail)); + //PRINT(("OpenSoundNode::_RunThread: I avail: %d\n", avail)); // skip if less than 1 buffer //if (avail < output->fOutput.format.u.raw_audio.buffer_size) @@ -2480,7 +2147,7 @@ OpenSoundNode::EngineRecThread(node_output *output) fDevice->Locker()->Unlock(); // Get the next buffer of data - BBuffer* buffer = FillNextBuffer(&abinfo, *output); + BBuffer* buffer = _FillNextBuffer(&abinfo, *output); fDevice->Locker()->Lock(); if (buffer) { @@ -2488,15 +2155,18 @@ OpenSoundNode::EngineRecThread(node_output *output) status_t err = B_ERROR; if (output->fOutputEnabled) err = SendBuffer(buffer, output->fOutput.destination); - //PRINT(("OpenSoundNode::RunThread: I avail: %d, OE %d, %s\n", avail, output->fOutputEnabled, strerror(err))); - if (err) { +// PRINT(("OpenSoundNode::_RunThread: I avail: %d, OE %d, %s\n", +// avail, output->fOutputEnabled, strerror(err))); + if (err != B_OK) { buffer->Recycle(); } else { // track how much media we've delivered so far - size_t nSamples = output->fOutput.format.u.raw_audio.buffer_size - / (output->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); + size_t nSamples = buffer->SizeUsed() + / (output->fOutput.format.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK); output->fSamplesSent += nSamples; - //PRINT(("OpenSoundNode::%s: sent %d samples\n", __FUNCTION__, nSamples)); +// PRINT(("OpenSoundNode::%s: sent %d samples\n", +// __FUNCTION__, nSamples)); } } @@ -2508,302 +2178,8 @@ OpenSoundNode::EngineRecThread(node_output *output) } -void -OpenSoundNode::WriteZeros(node_input &input, size_t len) -{ - char buffer[2048]; - OpenSoundDeviceEngine *engine = input.fRealEngine; - CALLED(); - - //size_t stride = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId].stride; - uint32 channelCount = input.fFormat.u.raw_audio.channel_count; - size_t chunk, left = len; - ssize_t done; - switch(input.fFormat.u.raw_audio.format) { - case media_raw_audio_format::B_AUDIO_FLOAT: -/* for(uint32 channel = 0; channel < channelCount; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(float*)sample_dest = 0; - sample_dest += stride; - } - }*/ - break; - case media_raw_audio_format::B_AUDIO_INT: - memset(buffer, 0, 2048); - break; - case media_raw_audio_format::B_AUDIO_SHORT: - memset(buffer, 0, 2048); - break; - default: - fprintf(stderr, "ERROR in WriteZeros format not handled\n"); - } -again: - chunk = MIN(left, 2048); - done = engine->Write(buffer, chunk); - if (done < 0) - return; - left -= done; - if (left) - goto again; - - -#if MA - /*int32 samples = input.fInput.format.u.raw_audio.buffer_size; - if(input.fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_UCHAR) { - uint8 *sample = (uint8*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; - for(int32 i = samples-1; i>=0; i--) - *sample++ = 128; - - } else { - int32 *sample = (int32*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; - for(int32 i = (samples / 4)-1; i>=0; i--) - *sample++ = 0;*/ - - size_t stride = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId].stride; - uint32 channelCount = input.fFormat.u.raw_audio.channel_count; - - switch(input.fFormat.u.raw_audio.format) { - case media_raw_audio_format::B_AUDIO_FLOAT: - for(uint32 channel = 0; channel < channelCount; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(float*)sample_dest = 0; - sample_dest += stride; - } - } - break; - case media_raw_audio_format::B_AUDIO_INT: - for(uint32 channel = 0; channel < channelCount; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(int32*)sample_dest = 0; - sample_dest += stride; - } - } - break; - case media_raw_audio_format::B_AUDIO_SHORT:{ - for(uint32 channel = 0; channel < channelCount; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(int16*)sample_dest = 0; - sample_dest += stride; - } - } - break; - } - default: - fprintf(stderr, "ERROR in WriteZeros format not handled\n"); - } -#endif -} - -void -OpenSoundNode::FillWithZeros(node_input &input) -{ - CALLED(); -#if MA - for(int32 i=0; iMBL.return_playback_buffers; i++) - WriteZeros(input, i); -#endif -} - -void -OpenSoundNode::FillNextBuffer(node_input &input, BBuffer* buffer) -{ - status_t err; - CALLED(); - OpenSoundDeviceEngine *engine = input.fRealEngine; - err = engine->Write(buffer->Data(), buffer->SizeUsed()); - -#if MA - switch(input.fInput.format.u.raw_audio.format) { - case media_raw_audio_format::B_AUDIO_FLOAT: - - switch(input.fFormat.u.raw_audio.format) { - case media_raw_audio_format::B_AUDIO_FLOAT: - break; - case media_raw_audio_format::B_AUDIO_INT: - break; - case media_raw_audio_format::B_AUDIO_SHORT: - if(input.fInput.format.u.raw_audio.channel_count == 2) { - int16 *sample_dest1 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; - int16 *sample_dest2 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].base; - float *sample_src = (float*)buffer->Data(); - if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == sizeof(int16) - && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == sizeof(int16)) { - //PRINT(("FillNextBuffer : 2 channels strides 2\n")); - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *sample_dest1++ = int16(32767 * *sample_src++); - *sample_dest2++ = int16(32767 * *sample_src++); - } - } else if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == 2 * sizeof(int16) - && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == 2 * sizeof(int16) - && sample_dest1 + 1 == sample_dest2) { - //PRINT(("FillNextBuffer : 2 channels strides 4\n")); - for(uint32 i=2*fDevice->MBL.return_playback_buffer_size; i>0; i--) - *sample_dest1++ = int16(32767 * *sample_src++); - } else { - //PRINT(("FillNextBuffer : 2 channels strides != 2\n")); - size_t stride1 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride / sizeof(int16); - size_t stride2 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride / sizeof(int16); - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *sample_dest1 = int16(32767 * *sample_src++); - *sample_dest2 = int16(32767 * *sample_src++); - sample_dest1 += stride1; - sample_dest2 += stride2; - } - } - } else { - size_t frame_size = input.fInput.format.u.raw_audio.channel_count * sizeof(int16); - size_t stride = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride; - //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->MBL.return_playback_buffer_size)); - for(uint32 channel = 0; channel < input.fInput.format.u.raw_audio.channel_count; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + channel].base; - //char *sample_src = (char*)buffer->Data() + (input.fInput.format.u.raw_audio.channel_count - 1 - channel) * sizeof(int16); - char *sample_src = (char*)buffer->Data() + channel * sizeof(int16); - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(int16*)sample_dest = int16(32767 * *(float*)sample_src); - sample_dest += stride; - sample_src += frame_size; - } - } - } - break; - default: - break; - } - - break; - case media_raw_audio_format::B_AUDIO_INT: - switch(input.fFormat.u.raw_audio.format) { - case media_raw_audio_format::B_AUDIO_FLOAT: - break; - case media_raw_audio_format::B_AUDIO_INT: { - size_t frame_size = input.fInput.format.u.raw_audio.channel_count * sizeof(int32); - size_t stride = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride; - //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->MBL.return_playback_buffer_size)); - for(uint32 channel = 0; channel < input.fInput.format.u.raw_audio.channel_count; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + channel].base; - //char *sample_src = (char*)buffer->Data() + (input.fInput.format.u.raw_audio.channel_count - 1 - channel) * sizeof(int16); - char *sample_src = (char*)buffer->Data() + channel * sizeof(int32); - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(int32*)sample_dest = *(int32*)sample_src; - sample_dest += stride; - sample_src += frame_size; - } - } - } - break; - case media_raw_audio_format::B_AUDIO_SHORT: - break; - default: - break; - } - break; - case media_raw_audio_format::B_AUDIO_SHORT: - - switch(input.fFormat.u.raw_audio.format) { - case media_raw_audio_format::B_AUDIO_FLOAT: - break; - case media_raw_audio_format::B_AUDIO_INT: - break; - case media_raw_audio_format::B_AUDIO_SHORT: - if(input.fInput.format.u.raw_audio.channel_count == 2) { - int16 *sample_dest1 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; - int16 *sample_dest2 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].base; - int16 *sample_src = (int16*)buffer->Data(); - if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == sizeof(int16) - && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == sizeof(int16)) { - //PRINT(("FillNextBuffer : 2 channels strides 2\n")); - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *sample_dest1++ = *sample_src++; - *sample_dest2++ = *sample_src++; - } - } else if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == 2 * sizeof(int16) - && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == 2 * sizeof(int16) - && sample_dest1 + 1 == sample_dest2) { - //PRINT(("FillNextBuffer : 2 channels strides 4\n")); - memcpy(sample_dest1, sample_src, fDevice->MBL.return_playback_buffer_size * 2 * sizeof(int16)); - } else { - //PRINT(("FillNextBuffer : 2 channels strides != 2\n")); - size_t stride1 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride / 2; - size_t stride2 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride / 2; - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *sample_dest1 = *sample_src++; - *sample_dest2 = *sample_src++; - sample_dest1 += stride1; - sample_dest2 += stride2; - } - } - } else { - size_t frame_size = input.fInput.format.u.raw_audio.channel_count * sizeof(int16); - size_t stride = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride; - //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->MBL.return_playback_buffer_size)); - for(uint32 channel = 0; channel < input.fInput.format.u.raw_audio.channel_count; channel++) { - char *sample_dest = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + channel].base; - //char *sample_src = (char*)buffer->Data() + (input.fInput.format.u.raw_audio.channel_count - 1 - channel) * sizeof(int16); - char *sample_src = (char*)buffer->Data() + channel * sizeof(int16); - for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { - *(int16*)sample_dest = *(int16*)sample_src; - sample_dest += stride; - sample_src += frame_size; - } - } - } - break; - default: - break; - } - - break; - case media_raw_audio_format::B_AUDIO_UCHAR: - default: - break; - } -#endif -} - status_t -OpenSoundNode::StartThread() -{ - CALLED(); - // the thread is already started ? - if(fThread > B_OK) - return B_OK; - - //allocate buffer free semaphore - int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX - -// fBufferAvailableSem = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" ); - fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" ); - - if ( fBufferAvailableSem < B_OK ) { - return B_ERROR; - } - - fThread = spawn_thread( _run_thread_, "OpenSound audio output", B_REAL_TIME_PRIORITY, this ); - - if ( fThread < B_OK ) { - delete_sem( fBufferAvailableSem ); - return B_ERROR; - } - - resume_thread( fThread ); - return B_OK; -} - -status_t -OpenSoundNode::StopThread() -{ - CALLED(); - delete_sem( fBufferAvailableSem ); - wait_for_thread( fThread, &fThread ); - return B_OK; -} - -status_t -OpenSoundNode::StartPlayThread(node_input *input) +OpenSoundNode::_StartPlayThread(NodeInput* input) { CALLED(); BAutolock L(fDevice->Locker()); @@ -2812,19 +2188,21 @@ OpenSoundNode::StartPlayThread(node_input *input) return B_OK; //allocate buffer free semaphore -// int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX - -// fBufferAvailableSem = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" ); -// fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" ); - -// if ( fBufferAvailableSem < B_OK ) { -// return B_ERROR; -// } +// int bufferCount = MAX(fDevice->fFragments.fragstotal, 2); // XXX - input->fThread = spawn_thread(_engine_play_thread_, "OpenSound audio output", B_REAL_TIME_PRIORITY, input); +// fBufferAvailableSem = create_sem(fDevice->MBL.return_playback_buffers - 1, +// "multi_audio out buffer free"); +// fBufferAvailableSem = create_sem(bufferCount - 1, +// "OpenSound out buffer free"); + +// if (fBufferAvailableSem < B_OK) +// return B_ERROR; + + input->fThread = spawn_thread(_PlayThreadEntry, + "OpenSound audio output", B_REAL_TIME_PRIORITY, input); if (input->fThread < B_OK) { -// delete_sem( fBufferAvailableSem ); +// delete_sem(fBufferAvailableSem); return B_ERROR; } @@ -2832,11 +2210,13 @@ OpenSoundNode::StartPlayThread(node_input *input) return B_OK; } + status_t -OpenSoundNode::StopPlayThread(node_input *input) +OpenSoundNode::_StopPlayThread(NodeInput* input) { + if (input->fThread < 0) + return B_OK; thread_id th; - status_t ret; CALLED(); { BAutolock L(fDevice->Locker()); @@ -2844,12 +2224,14 @@ OpenSoundNode::StopPlayThread(node_input *input) input->fThread = -1; //kill(th, SIGUSR1); } + status_t ret; wait_for_thread(th, &ret); return B_OK; } + status_t -OpenSoundNode::StartRecThread(node_output *output) +OpenSoundNode::_StartRecThread(NodeOutput* output) { CALLED(); // the thread is already started ? @@ -2857,19 +2239,21 @@ OpenSoundNode::StartRecThread(node_output *output) return B_OK; //allocate buffer free semaphore -// int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX +// int bufferCount = MAX(fDevice->fFragments.fragstotal, 2); // XXX -// fBufferAvailableSem = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" ); -// fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" ); +// fBufferAvailableSem = create_sem(fDevice->MBL.return_playback_buffers - 1, +// "multi_audio out buffer free"); +// fBufferAvailableSem = create_sem(bufferCount - 1, +// "OpenSound out buffer free"); -// if ( fBufferAvailableSem < B_OK ) { +// if (fBufferAvailableSem < B_OK) // return B_ERROR; -// } - output->fThread = spawn_thread(_engine_rec_thread_, "OpenSound audio input", B_REAL_TIME_PRIORITY, output); + output->fThread = spawn_thread(_RecThreadEntry, "OpenSound audio input", + B_REAL_TIME_PRIORITY, output); if (output->fThread < B_OK) { - //delete_sem( fBufferAvailableSem ); + //delete_sem(fBufferAvailableSem); return B_ERROR; } @@ -2877,23 +2261,27 @@ OpenSoundNode::StartRecThread(node_output *output) return B_OK; } + status_t -OpenSoundNode::StopRecThread(node_output *output) +OpenSoundNode::_StopRecThread(NodeOutput* output) { + if (output->fThread < 0) + return B_OK; thread_id th = output->fThread; - status_t ret; output->fThread = -1; CALLED(); { BAutolock L(fDevice->Locker()); //kill(th, SIGUSR1); } + status_t ret; wait_for_thread(th, &ret); return B_OK; } + void -OpenSoundNode::AllocateBuffers(node_output &channel) +OpenSoundNode::_AllocateBuffers(NodeOutput& channel) { CALLED(); @@ -2901,49 +2289,51 @@ OpenSoundNode::AllocateBuffers(node_output &channel) size_t size = channel.fOutput.format.u.raw_audio.buffer_size; int32 count = int32(fLatency / BufferDuration() + 1 + 1); - PRINT(("\tlatency = %Ld, buffer duration = %Ld\n", fLatency, BufferDuration())); + PRINT(("\tlatency = %Ld, buffer duration = %Ld\n", fLatency, + BufferDuration())); PRINT(("\tcreating group of %ld buffers, size = %lu\n", count, size)); channel.fBufferGroup = new BBufferGroup(size, count); } + void -OpenSoundNode::UpdateTimeSource(audio_buf_info *abinfo, node_input &input) +OpenSoundNode::_UpdateTimeSource(audio_buf_info* abinfo, NodeInput& input) { OpenSoundDeviceEngine *engine = input.fRealEngine; /**/CALLED(); if (!engine) return; - if(fTimeSourceStarted) { + if (fTimeSourceStarted) { int64 played_frames = engine->PlayedFramesCount(); - bigtime_t perf_time = (bigtime_t)(played_frames / - input.fInput.format.u.raw_audio.frame_rate * 1000000LL); - bigtime_t real_time = engine->PlayedRealTime(); //XXX! - //MBI.played_real_time; - /* - PRINT(("TS: frames: last %Ld curr %Ld diff %Ld, time: last %Ld curr %Ld diff %Ld\n", - fOldPlayedFramesCount, played_frames, played_frames - fOldPlayedFramesCount, - fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime)); - */ + bigtime_t perf_time = (bigtime_t)(played_frames + / input.fInput.format.u.raw_audio.frame_rate * 1000000LL); + bigtime_t real_time = engine->PlayedRealTime(); // XXX! + // MBI.played_real_time; +// PRINT(("TS: frames: last %Ld curr %Ld diff %Ld, time: last %Ld curr " +// "%Ld diff %Ld\n", +// fOldPlayedFramesCount, played_frames, played_frames +// - fOldPlayedFramesCount, +// fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime)); float drift; if (real_time - fOldPlayedRealTime) drift = ((played_frames - fOldPlayedFramesCount) - / input.fInput.format.u.raw_audio.frame_rate * 1000000LL) - / (real_time - fOldPlayedRealTime); + / input.fInput.format.u.raw_audio.frame_rate * 1000000LL) + / (real_time - fOldPlayedRealTime); else drift = 1; if (!drift) drift = 1; -// drift = 1; -/* fprintf(stderr, "TS: frames: last %Ld curr %Ld diff %Ld, time: last %Ld curr %Ld diff %Ld, drift %f\n", - fOldPlayedFramesCount, played_frames, played_frames - fOldPlayedFramesCount, - fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime, drift);*/ +// fprintf(stderr, "TS: frames: last %Ld curr %Ld diff %Ld, time: " +// "last %Ld curr %Ld diff %Ld, drift %f\n", +// fOldPlayedFramesCount, played_frames, played_frames +// - fOldPlayedFramesCount, +// fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime, +// drift); // drift = 1 + (drift - 1) / 10; - /* - * In theory we should pass it, but it seems to work better if we fake a perfect world... - * Maybe it interferes with OSS's queing. - */ + // In theory we should pass it, but it seems to work better if we fake + // a perfect world... Maybe it interferes with OSS's queing. #ifdef DISABLE_DRIFT drift = 1; #endif @@ -2952,288 +2342,203 @@ OpenSoundNode::UpdateTimeSource(audio_buf_info *abinfo, node_input &input) fOldPlayedFramesCount = played_frames; fOldPlayedRealTime = real_time; - //PRINT(("UpdateTimeSource() perf_time : %lli, real_time : %lli, drift : %f\n", perf_time, real_time, drift)); +// PRINT(("_UpdateTimeSource() perf_time : %lli, real_time : %lli, +// drift : %f\n", perf_time, real_time, drift)); } } -#if MA -void -OpenSoundNode::UpdateTimeSource(multi_buffer_info &MBI, multi_buffer_info &oldMBI, node_input &input) -{ - //CALLED(); - if(fTimeSourceStarted) { - bigtime_t perf_time = (bigtime_t)(MBI.played_frames_count / - input.fInput.format.u.raw_audio.frame_rate * 1000000); - bigtime_t real_time = MBI.played_real_time; - float drift = ((MBI.played_frames_count - oldMBI.played_frames_count) - / input.fInput.format.u.raw_audio.frame_rate * 1000000) - / (MBI.played_real_time - oldMBI.played_real_time); - - PublishTime(perf_time, real_time, drift); - //PRINT(("UpdateTimeSource() perf_time : %lli, real_time : %lli, drift : %f\n", perf_time, real_time, drift)); - } -} BBuffer* -OpenSoundNode::FillNextBuffer(multi_buffer_info &MBI, node_output &channel) -{ - //CALLED(); - // get a buffer from our buffer group - //PRINT(("buffer size : %i, buffer duration : %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration())); - //PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle)); - //PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time)); - //PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count)); - if(!channel.fBufferGroup) - return NULL; - - BBuffer* buffer = channel.fBufferGroup->RequestBuffer(channel.fOutput.format.u.raw_audio.buffer_size, BufferDuration()); - - // if we fail to get a buffer (for example, if the request times out), we skip this - // buffer and go on to the next, to avoid locking up the control thread - if (!buffer) - return NULL; - - if(fDevice==NULL) - fprintf(stderr,"fDevice NULL\n"); - if(buffer->Header()==NULL) - fprintf(stderr,"buffer->Header() NULL\n"); - if(TimeSource()==NULL) - fprintf(stderr,"TimeSource() NULL\n"); - - // now fill it with data, continuing where the last buffer left off - memcpy( buffer->Data(), - fDevice->MBL.record_buffers[MBI.record_buffer_cycle][channel.fChannelId - fDevice->MD.output_channel_count].base, - channel.fOutput.format.u.raw_audio.buffer_size ); - - // fill in the buffer header - media_header* hdr = buffer->Header(); - hdr->type = B_MEDIA_RAW_AUDIO; - hdr->size_used = channel.fOutput.format.u.raw_audio.buffer_size; - hdr->time_source = TimeSource()->ID(); - hdr->start_time = PerformanceTimeFor(MBI.recorded_real_time); - - return buffer; -} -#endif - -BBuffer* -OpenSoundNode::FillNextBuffer(audio_buf_info *abinfo, node_output &channel) -{ - OpenSoundDeviceEngine *engine = channel.fRealEngine; - //CALLED(); - // get a buffer from our buffer group - //PRINT(("buffer size : %i, buffer duration : %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration())); - //PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle)); - //PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time)); - //PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count)); - if(!channel.fBufferGroup) - return NULL; - - BBuffer* buffer = channel.fBufferGroup->RequestBuffer(channel.fOutput.format.u.raw_audio.buffer_size, BufferDuration()); - - // if we fail to get a buffer (for example, if the request times out), we skip this - // buffer and go on to the next, to avoid locking up the control thread - if (!buffer) - return NULL; - - if(fDevice==NULL) - fprintf(stderr,"fDevice NULL\n"); - if(buffer->Header()==NULL) - fprintf(stderr,"buffer->Header() NULL\n"); - if(TimeSource()==NULL) - fprintf(stderr,"TimeSource() NULL\n"); - - // now fill it with data - ssize_t used = engine->Read(buffer->Data(), channel.fOutput.format.u.raw_audio.buffer_size); - if (used < 0) { - PRINT(("OpenSoundNode::%s: %s\n", __FUNCTION__, strerror(used))); - buffer->Recycle(); - return NULL; - } - if (used < channel.fOutput.format.u.raw_audio.buffer_size) { - PRINT(("OpenSoundNode::%s: requested %d, got %d\n", __FUNCTION__, channel.fOutput.format.u.raw_audio.buffer_size, used)); - } - // fill in the buffer header - media_header* hdr = buffer->Header(); - hdr->type = B_MEDIA_RAW_AUDIO; - hdr->size_used = used;//channel.fOutput.format.u.raw_audio.buffer_size; - hdr->time_source = TimeSource()->ID(); - //XXX: should be system_time() - latency_as_per(abinfo) - hdr->start_time = PerformanceTimeFor(system_time()); - - return buffer; -} - -status_t -OpenSoundNode::GetConfigurationFor(BMessage * into_message) +OpenSoundNode::_FillNextBuffer(audio_buf_info* abinfo, NodeOutput& channel) { CALLED(); + + BBuffer* buffer = channel.FillNextBuffer(BufferDuration()); + if (!buffer) + return NULL; - BParameter *parameter = NULL; - void *buffer; - size_t size = 128; - bigtime_t last_change; - status_t err; + if (fDevice == NULL) + fprintf(stderr, "OpenSoundNode::_FillNextBuffer() - fDevice NULL\n"); + if (buffer->Header() == NULL) { + fprintf(stderr, "OpenSoundNode::_FillNextBuffer() - " + "buffer->Header() NULL\n"); + } + if (TimeSource() == NULL) { + fprintf(stderr, "OpenSoundNode::_FillNextBuffer() - " + "TimeSource() NULL\n"); + } - if(!into_message) + // fill in the buffer header + media_header* hdr = buffer->Header(); + if (hdr != NULL) { + hdr->time_source = TimeSource()->ID(); + // TODO: should be system_time() - latency_as_per(abinfo) + hdr->start_time = PerformanceTimeFor(system_time()); + } + + return buffer; +} + + +status_t +OpenSoundNode::GetConfigurationFor(BMessage* into_message) +{ + CALLED(); + + if (!into_message) return B_BAD_VALUE; - - buffer = malloc(size); - - for(int32 i=0; iCountParameters(); i++) { - parameter = fWeb->ParameterAt(i); - if(parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER + + size_t size = 128; + void* buffer = malloc(size); + + for (int32 i = 0; i < fWeb->CountParameters(); i++) { + BParameter* parameter = fWeb->ParameterAt(i); + if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER && parameter->Type() != BParameter::B_DISCRETE_PARAMETER) continue; PRINT(("getting parameter %i\n", parameter->ID())); size = 128; - while((err = GetParameterValue(parameter->ID(), &last_change, buffer, &size))==B_NO_MEMORY) { + bigtime_t last_change; + status_t err; + while ((err = GetParameterValue(parameter->ID(), &last_change, buffer, + &size)) == B_NO_MEMORY) { size += 128; free(buffer); buffer = malloc(size); } - if(err == B_OK && size > 0) { + if (err == B_OK && size > 0) { into_message->AddInt32("parameterID", parameter->ID()); - into_message->AddData("parameterData", B_RAW_TYPE, buffer, size, false); + into_message->AddData("parameterData", B_RAW_TYPE, buffer, size, + false); } else { PRINT(("parameter err : %s\n", strerror(err))); } } - + + free(buffer); + PRINT_OBJECT(*into_message); - + return B_OK; } -node_output* -OpenSoundNode::FindOutput(media_source source) -{ - node_output *channel = NULL; - for(int32 i=0; ifOutput.source) - break; +OpenSoundNode::NodeOutput* +OpenSoundNode::_FindOutput(const media_source& source) const +{ + int32 count = fOutputs.CountItems(); + for (int32 i = 0; i < count; i++) { + NodeOutput* channel = (NodeOutput*)fOutputs.ItemAtFast(i); + if (source == channel->fOutput.source) + return channel; } - - if (source != channel->fOutput.source) - return NULL; - else - return channel; - + return NULL; } -node_input* -OpenSoundNode::FindInput(media_destination dest) -{ - node_input *channel = NULL; - for(int32 i=0; ifInput.destination) - break; +OpenSoundNode::NodeInput* +OpenSoundNode::_FindInput(const media_destination& dest) const +{ + int32 count = fInputs.CountItems(); + for (int32 i = 0; i < count; i++) { + NodeInput* channel = (NodeInput*)fInputs.ItemAtFast(i); + if (dest == channel->fInput.destination) + return channel; } - - if (dest != channel->fInput.destination) - return NULL; - else - return channel; - + return NULL; } -node_input* -OpenSoundNode::FindInput(int32 destinationId) -{ - node_input *channel = NULL; - for(int32 i=0; ifInput.destination.id) - break; +OpenSoundNode::NodeInput* +OpenSoundNode::_FindInput(int32 destinationId) +{ + int32 count = fInputs.CountItems(); + for (int32 i = 0; i < fInputs.CountItems(); i++) { + NodeInput* channel = (NodeInput*)fInputs.ItemAtFast(i); + if (destinationId == channel->fInput.destination.id) + return channel; } - - if (destinationId != channel->fInput.destination.id) - return NULL; - else - return channel; - + return NULL; } -// static: + +// pragma mark - static + + +void +OpenSoundNode::_SignalHandler(int sig) +{ + // TODO: what was this intended for, just stopping the threads? + // (see _StopThreadXXX(), there is a kill call commented out there) +} int32 -OpenSoundNode::_run_thread_( void *data ) +OpenSoundNode::_PlayThreadEntry(void* data) { CALLED(); -#if 0 - return static_cast( data )->RunThread(); -#endif + NodeInput *channel = static_cast(data); + return channel->fNode->_PlayThread(channel); +} + + +int32 +OpenSoundNode::_RecThreadEntry(void* data) +{ + CALLED(); + NodeOutput *channel = static_cast(data); + return channel->fNode->_RecThread(channel); } void -OpenSoundNode::_sig_handler_(int sig) -{ -} - -int32 -OpenSoundNode::_engine_play_thread_(void *data) +OpenSoundNode::GetFlavor(flavor_info* outInfo, int32 id) { CALLED(); - node_input *channel = static_cast(data); - return channel->fNode->EnginePlayThread(channel); -} - - -int32 -OpenSoundNode::_engine_rec_thread_(void *data) -{ - CALLED(); - node_output *channel = static_cast(data); - return channel->fNode->EngineRecThread(channel); -} - - -void OpenSoundNode::GetFlavor(flavor_info * outInfo, int32 id) -{ - CALLED(); - if (outInfo == 0) { + if (outInfo == NULL) return; - } outInfo->flavor_flags = 0; - outInfo->possible_count = 1; // one flavor at a time - outInfo->in_format_count = 0; // no inputs + outInfo->possible_count = 1; + // one flavor at a time + outInfo->in_format_count = 0; + // no inputs outInfo->in_formats = 0; - outInfo->out_format_count = 0; // no outputs + outInfo->out_format_count = 0; + // no outputs outInfo->out_formats = 0; outInfo->internal_id = id; - + outInfo->name = "OpenSoundNode Node"; - outInfo->info = "The OpenSoundNode node outputs to OpenSound System v4 drivers."; + outInfo->info = "The OpenSoundNode outputs to OpenSound System v4 " + "drivers."; outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE - | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE; - //XXX:B_MEDIA_ENCODED_AUDIO - outInfo->in_format_count = 1; // 1 input + | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE; + // TODO: If the OSS engine supports outputing encoded audio, + // we would need to setup a B_MEDIA_ENCODED_AUDIO format here + outInfo->in_format_count = 1; + // 1 input media_format * informats = new media_format[outInfo->in_format_count]; GetFormat(&informats[0]); outInfo->in_formats = informats; - outInfo->out_format_count = 1; // 1 output + outInfo->out_format_count = 1; + // 1 output media_format * outformats = new media_format[outInfo->out_format_count]; GetFormat(&outformats[0]); outInfo->out_formats = outformats; } -void OpenSoundNode::GetFormat(media_format * outFormat) + +void +OpenSoundNode::GetFormat(media_format* outFormat) { CALLED(); - if (outFormat == 0) { + if (outFormat == NULL) return; - } + outFormat->type = B_MEDIA_RAW_AUDIO; outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; diff --git a/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h b/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h index 7b0425f287..17f2678329 100644 --- a/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h +++ b/src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h @@ -2,436 +2,284 @@ * OpenSound media addon for BeOS and Haiku * * Copyright (c) 2007, François Revol (revol@free.fr) - * Distributed under the terms of the MIT License. - * - * Based on MultiAudio media addon * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) - * - * All rights reserved. - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 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. + * Distributed under the terms of the MIT License. * */ #ifndef _OPENSOUNDNODE_H #define _OPENSOUNDNODE_H -#include -#include -#include #include #include #include #include +#include +#include #include #include -#include -#include -#include -#include -//#include "soundcard.h" -#include "OpenSoundDevice.h" -#include "OpenSoundDeviceEngine.h" -#include "OpenSoundDeviceMixer.h" -/*bool format_is_acceptible( - const media_format & producer_format, - const media_format & consumer_format);*/ - -class OpenSoundNode; +class OpenSoundDevice; +class OpenSoundDeviceEngine; +class OpenSoundDeviceMixer; + +struct audio_buf_info; + + +class OpenSoundNode : public BBufferConsumer, public BBufferProducer, + public BTimeSource, public BMediaEventLooper, public BControllable { + +private: + class NodeInput; + class NodeOutput; + +protected: + virtual ~OpenSoundNode(); + +public: + explicit OpenSoundNode(BMediaAddOn* addon, + const char* name, + OpenSoundDevice* device, + int32 internalID, BMessage* config); + + virtual status_t InitCheck() const; + + // BMediaNode interface +public: + virtual BMediaAddOn* AddOn(int32* internalID) const; + // Who instantiated you -- or NULL for app class + +protected: + virtual void Preroll(); + // These don't return errors; instead, they use the global error + // condition reporter. A node is required to have a queue of at + // least one pending command (plus TimeWarp) and is recommended to + // allow for at least one pending command of each type. Allowing an + // arbitrary number of outstanding commands might be nice, but apps + // cannot depend on that happening. + +public: + virtual status_t HandleMessage(int32 message, + const void* data, size_t size); -class node_input -{ - public: - node_input(media_input &input, media_format format); - ~node_input(); +protected: + virtual void NodeRegistered(); + virtual status_t RequestCompleted( + const media_request_info& info); + virtual void SetTimeSource(BTimeSource* timeSource); - OpenSoundNode *fNode; - int32 fEngineId; - OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId) - int fAFmt; // AFMT_* for this one - int32 fChannelId; - media_input fInput; - media_format fPreferredFormat; - media_format fFormat; + // BBufferConsumer interface +protected: + virtual status_t AcceptFormat( + const media_destination& dest, + media_format* format); + // Someone, probably the producer, is asking you about this format. + // Give your honest opinion, possibly modifying *format. Do not ask + // upstream producer about the format, since he's synchronously + // waiting for your reply. + virtual status_t GetNextInput(int32* cookie, + media_input* out_input); + virtual void DisposeInputCookie(int32 cookie); + virtual void BufferReceived(BBuffer* buffer); + virtual void ProducerDataStatus( + const media_destination& for_whom, + int32 status, + bigtime_t at_performance_time); + virtual status_t GetLatencyFor( + const media_destination& for_whom, + bigtime_t* out_latency, + media_node_id* out_timesource); + virtual status_t Connected(const media_source& producer, + const media_destination& where, + const media_format& with_format, + media_input* out_input); + // here's a good place to request buffer group usage - thread_id fThread; - uint32 fBufferCycle; -// multi_buffer_info fOldMBI; -// BBuffer *fBuffer; - BList fBuffers; // of (BBuffer *) -}; + virtual void Disconnected(const media_source& producer, + const media_destination& where); -class node_output -{ - public: - node_output(media_output &output, media_format format); - ~node_output(); + virtual status_t FormatChanged(const media_source& producer, + const media_destination& consumer, + int32 change_tag, + const media_format& format); - OpenSoundNode *fNode; - int32 fEngineId; - OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId) - int fAFmt; // AFMT_* for this one - int32 fChannelId; - media_output fOutput; - media_format fPreferredFormat; - media_format fFormat; + virtual status_t SeekTagRequested( + const media_destination& destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag* out_seek_tag, + bigtime_t* out_tagged_time, + uint32* out_flags); + + // BBufferProducer interface +protected: + virtual status_t FormatSuggestionRequested(media_type type, + int32 quality, media_format* format); - thread_id fThread; - BBufferGroup *fBufferGroup; - bool fOutputEnabled; - uint64 fSamplesSent; - volatile uint32 fBufferCycle; -// multi_buffer_info fOldMBI; -}; + virtual status_t FormatProposal(const media_source& output, + media_format* format); + + virtual status_t FormatChangeRequested( + const media_source& source, + const media_destination& destination, + media_format* io_format, + int32* _deprecated_); + virtual status_t GetNextOutput(int32* cookie, + media_output* out_output); + virtual status_t DisposeOutputCookie(int32 cookie); + + virtual status_t SetBufferGroup( + const media_source& for_source, + BBufferGroup* group); + + virtual status_t PrepareToConnect(const media_source& what, + const media_destination& where, + media_format* format, + media_source* out_source, + char* out_name); + + virtual void Connect(status_t error, + const media_source& source, + const media_destination& destination, + const media_format& format, + char* io_name); + + virtual void Disconnect(const media_source& what, + const media_destination& where); + + virtual void LateNoticeReceived( + const media_source& what, + bigtime_t how_much, + bigtime_t performance_time); + + virtual void EnableOutput(const media_source& what, + bool enabled, int32* _deprecated_); + virtual void AdditionalBufferRequested( + const media_source& source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag* prev_tag); -class OpenSoundNode : - public BBufferConsumer, - public BBufferProducer, - public BTimeSource, - public BMediaEventLooper, - public BControllable -{ + // BMediaEventLooper interface protected: -virtual ~OpenSoundNode(void); - -public: - -explicit OpenSoundNode(BMediaAddOn *addon, char* name, OpenSoundDevice *device, - int32 internal_id, BMessage * config); - -virtual status_t InitCheck(void) const; - -/*************************/ -/* begin from BMediaNode */ -public: -virtual BMediaAddOn* AddOn( - int32 * internal_id) const; /* Who instantiated you -- or NULL for app class */ - -protected: - /* These don't return errors; instead, they use the global error condition reporter. */ - /* A node is required to have a queue of at least one pending command (plus TimeWarp) */ - /* and is recommended to allow for at least one pending command of each type. */ - /* Allowing an arbitrary number of outstanding commands might be nice, but apps */ - /* cannot depend on that happening. */ -virtual void Preroll(void); - -public: -virtual status_t HandleMessage( - int32 message, - const void * data, - size_t size); - -protected: -virtual void NodeRegistered(void); /* reserved 2 */ -virtual status_t RequestCompleted(const media_request_info &info); -virtual void SetTimeSource(BTimeSource *timeSource); - -/* end from BMediaNode */ -/***********************/ - -/******************************/ -/* begin from BBufferConsumer */ - -//included from BMediaAddOn -//virtual status_t HandleMessage( -// int32 message, -// const void * data, -// size_t size); - - /* Someone, probably the producer, is asking you about this format. Give */ - /* your honest opinion, possibly modifying *format. Do not ask upstream */ - /* producer about the format, since he's synchronously waiting for your */ - /* reply. */ -virtual status_t AcceptFormat( - const media_destination & dest, - media_format * format); -virtual status_t GetNextInput( - int32 * cookie, - media_input * out_input); -virtual void DisposeInputCookie( - int32 cookie); -virtual void BufferReceived( - BBuffer * buffer); -virtual void ProducerDataStatus( - const media_destination & for_whom, - int32 status, - bigtime_t at_performance_time); -virtual status_t GetLatencyFor( - const media_destination & for_whom, - bigtime_t * out_latency, - media_node_id * out_timesource); -virtual status_t Connected( - const media_source & producer, /* here's a good place to request buffer group usage */ - const media_destination & where, - const media_format & with_format, - media_input * out_input); -virtual void Disconnected( - const media_source & producer, - const media_destination & where); - /* The notification comes from the upstream producer, so he's already cool with */ - /* the format; you should not ask him about it in here. */ -virtual status_t FormatChanged( - const media_source & producer, - const media_destination & consumer, - int32 change_tag, - const media_format & format); - - /* Given a performance time of some previous buffer, retrieve the remembered tag */ - /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ - /* idea being that flags can be added later, and the understood flags returned in */ - /* *out_flags. */ -virtual status_t SeekTagRequested( - const media_destination & destination, - bigtime_t in_target_time, - uint32 in_flags, - media_seek_tag * out_seek_tag, - bigtime_t * out_tagged_time, - uint32 * out_flags); - -/* end from BBufferConsumer */ -/****************************/ - -/******************************/ -/* begin from BBufferProducer */ - - virtual status_t FormatSuggestionRequested( media_type type, - int32 quality, - media_format* format); - - virtual status_t FormatProposal( const media_source& output, - media_format* format); - - virtual status_t FormatChangeRequested( const media_source& source, - const media_destination& destination, - media_format* io_format, - int32* _deprecated_); - virtual status_t GetNextOutput( int32* cookie, - media_output* out_output); - virtual status_t DisposeOutputCookie( int32 cookie); - - virtual status_t SetBufferGroup( const media_source& for_source, - BBufferGroup* group); - - virtual status_t PrepareToConnect( const media_source& what, - const media_destination& where, - media_format* format, - media_source* out_source, - char* out_name); - - virtual void Connect( status_t error, - const media_source& source, - const media_destination& destination, - const media_format& format, - char* io_name); - - virtual void Disconnect( const media_source& what, - const media_destination& where); - - virtual void LateNoticeReceived( const media_source& what, - bigtime_t how_much, - bigtime_t performance_time); - - virtual void EnableOutput( const media_source & what, - bool enabled, - int32* _deprecated_); - virtual void AdditionalBufferRequested( const media_source& source, - media_buffer_id prev_buffer, - bigtime_t prev_time, - const media_seek_tag* prev_tag); - -/* end from BBufferProducer */ -/****************************/ - -/*****************/ -/* BControllable */ -/*****************/ - -/********************************/ -/* start from BMediaEventLooper */ - - protected: /* you must override to handle your events! */ /* you should not call HandleEvent directly */ - virtual void HandleEvent( const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); - -/* end from BMediaEventLooper */ -/******************************/ - -/********************************/ -/* start from BTimeSource */ - protected: - virtual void SetRunMode( run_mode mode); - virtual status_t TimeSourceOp( const time_source_op_info &op, - void *_reserved); - -/* end from BTimeSource */ -/******************************/ - -/********************************/ -/* start from BControllable */ - protected: - virtual status_t GetParameterValue( int32 id, - bigtime_t* last_change, - void* value, - size_t* ioSize); - virtual void SetParameterValue( int32 id, - bigtime_t when, - const void* value, - size_t size); - virtual BParameterWeb* MakeParameterWeb(); - - status_t PropagateParameterChanges(int from, int type, const char *id); - -/* end from BControllable */ -/******************************/ + virtual void HandleEvent(const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + // BTimeSource interface protected: + virtual void SetRunMode(run_mode mode); + virtual status_t TimeSourceOp(const time_source_op_info& op, + void* _reserved); -virtual status_t HandleStart( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); -virtual status_t HandleSeek( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); -virtual status_t HandleWarp( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); -virtual status_t HandleStop( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); -virtual status_t HandleBuffer( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); -virtual status_t HandleDataStatus( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); -virtual status_t HandleParameter( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false); + // BControllable interface +protected: + virtual status_t GetParameterValue(int32 id, + bigtime_t* last_change, + void* value, size_t* ioSize); + virtual void SetParameterValue(int32 id, + bigtime_t when, const void* value, + size_t size); + virtual BParameterWeb* MakeParameterWeb(); + +private: + void _ProcessGroup(BParameterGroup* group, + int32 index, int32& _parameters); + void _ProcessMux(BDiscreteParameter* parameter, + int32 index); + status_t _PropagateParameterChanges(int from, + int type, const char* id); + +protected: + virtual status_t HandleStart(const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + virtual status_t HandleSeek(const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + virtual status_t HandleWarp(const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + virtual status_t HandleStop(const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + virtual status_t HandleBuffer( + const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + virtual status_t HandleDataStatus( + const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); + virtual status_t HandleParameter( + const media_timed_event* event, + bigtime_t lateness, + bool realTimeEvent = false); public: + static void GetFlavor(flavor_info* outInfo, int32 id); + static void GetFormat(media_format* outFormat); -static void GetFlavor(flavor_info * outInfo, int32 id); -static void GetFormat(media_format * outFormat); - -status_t GetConfigurationFor(BMessage * into_message); + status_t GetConfigurationFor(BMessage* intoMessage); private: - - OpenSoundNode( /* private unimplemented */ - const OpenSoundNode & clone); - OpenSoundNode & operator=( - const OpenSoundNode & clone); + OpenSoundNode(const OpenSoundNode& clone); + // private unimplemented + OpenSoundNode& operator=(const OpenSoundNode& clone); - //void WriteBuffer( BBuffer *buffer, node_input &input ); - //void WriteZeros(node_input &input, uint32 bufferCycle); - void WriteZeros(node_input &input, size_t len); - void FillWithZeros(node_input &input); - void FillNextBuffer(node_input &channel, BBuffer* buffer); +private: + static void _SignalHandler(int sig); - static int32 _run_thread_( void *data ); - int32 RunThread(); - status_t StartThread(); - status_t StopThread(); - - static void _sig_handler_(int sig); - static int32 _engine_play_thread_( void *data ); - static int32 _engine_rec_thread_( void *data ); - int32 EnginePlayThread(node_input *input); - int32 EngineRecThread(node_output *output); + static int32 _PlayThreadEntry(void* data); + static int32 _RecThreadEntry(void* data); + int32 _PlayThread(NodeInput* input); + int32 _RecThread(NodeOutput* output); - status_t StartPlayThread(node_input *input); - status_t StopPlayThread(node_input *input); - status_t StartRecThread(node_output *output); - status_t StopRecThread(node_output *output); + status_t _StartPlayThread(NodeInput* input); + status_t _StopPlayThread(NodeInput* input); + status_t _StartRecThread(NodeOutput* output); + status_t _StopRecThread(NodeOutput* output); - void AllocateBuffers(node_output &channel); - BBuffer* FillNextBuffer(audio_buf_info *abinfo, node_output &channel); -// BBuffer* FillNextBuffer( multi_buffer_info &MBI, -// node_output &channel); -// void UpdateTimeSource(multi_buffer_info &MBI, -// multi_buffer_info &oldMBI, -// node_input &input); - void UpdateTimeSource(audio_buf_info *abinfo, - node_input &input); + void _AllocateBuffers(NodeOutput& channel); + BBuffer* _FillNextBuffer(audio_buf_info* abinfo, + NodeOutput& channel); + void _UpdateTimeSource(audio_buf_info* abinfo, + NodeInput& input); - node_output* FindOutput(media_source source); - node_input* FindInput(media_destination dest); - node_input* FindInput(int32 destinationId); + NodeOutput* _FindOutput( + const media_source& source) const; + NodeInput* _FindInput( + const media_destination& dest) const; + NodeInput* _FindInput(int32 destinationId); - void ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParameters); - void ProcessMux(BDiscreteParameter *parameter, int32 index); - - status_t fInitCheckStatus; +private: + status_t fInitCheckStatus; - BMediaAddOn *fAddOn; - int32 fId; + BMediaAddOn* fAddOn; + int32 fId; - BList fInputs; + BList fInputs; + BList fOutputs; - bigtime_t fLatency; - BList fOutputs; #if 1 - media_format fPreferredFormat; + // TODO: remove and use use a preferred format + // per NodeInput/NodeOutput channel + media_format fPreferredFormat; #endif - - bigtime_t fInternalLatency; - // this is computed from the real (negotiated) chunk size and bit rate, - // not the defaults that are in the parameters - bigtime_t fBufferPeriod; - - - //volatile uint32 fBufferCycle; - sem_id fBufferAvailableSem; - - - thread_id fThread; - - OpenSoundDevice *fDevice; - - //multi_description MD; - //multi_format_info MFI; - //multi_buffer_list MBL; - - //multi_mix_control_info MMCI; - //multi_mix_control MMC[MAX_CONTROLS]; - - bool fTimeSourceStarted; - - int64 fOldPlayedFramesCount; - bigtime_t fOldPlayedRealTime; - - BParameterWeb *fWeb; - - BMessage fConfig; + bigtime_t fLatency; + bigtime_t fInternalLatency; + // this is computed from the real (negotiated) chunk size + // and bit rate, not the defaults that are in the + // parameters + OpenSoundDevice* fDevice; + bool fTimeSourceStarted; + int64 fOldPlayedFramesCount; + bigtime_t fOldPlayedRealTime; + BParameterWeb* fWeb; + BMessage fConfig; }; -#endif /* _OPENSOUNDNODE_H */ +#endif // _OPENSOUNDNODE_H