* Use shared AutoDeleter.h instead of custom array deleter.

* Improve code in FileUtils to copy attributes in chunks and improve
  error checking. Should also copy 0 size attributes now, since those are valid.
* Craft SoundConsumer towards more style guide compliance.
* Use new (std::nothrow) and check result.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26717 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2008-08-01 14:16:05 +00:00
parent d2d52d31ab
commit c1c81d42d1
6 changed files with 335 additions and 389 deletions
+68 -30
View File
@@ -7,14 +7,22 @@
/ Copyright 1998-1999, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#include <stdio.h>
#include <fs_attr.h>
#include "array_delete.h"
#include "FileUtils.h"
status_t CopyFileData(BFile& dst, BFile& src)
#include <new>
#include <stdio.h>
#include <string.h>
#include <fs_attr.h>
#include "AutoDeleter.h"
using std::nothrow;
status_t
CopyFileData(BFile& dst, BFile& src)
{
struct stat src_stat;
status_t err = src.GetStat(&src_stat);
@@ -24,12 +32,13 @@ status_t CopyFileData(BFile& dst, BFile& src)
}
size_t bufSize = src_stat.st_blksize;
if (! bufSize) {
if (bufSize == 0)
bufSize = 32768;
}
char* buf = new char[bufSize];
array_delete<char> bufDelete(buf);
char* buf = new (nothrow) char[bufSize];
if (buf == NULL)
return B_NO_MEMORY;
ArrayDeleter<char> _(buf);
printf("copy data, bufSize = %ld\n", bufSize);
// copy data
@@ -38,14 +47,18 @@ status_t CopyFileData(BFile& dst, BFile& src)
if (bytes > 0) {
ssize_t result = dst.Write(buf, bytes);
if (result != bytes) {
printf("result = %#010lx, bytes = %#010lx\n", (uint32) result,
(uint32) bytes);
return B_ERROR;
fprintf(stderr, "Failed to write %ld bytes: %s\n", bytes,
strerror((status_t)result));
if (result < 0)
return (status_t)result;
else
return B_IO_ERROR;
}
} else {
if (bytes < 0) {
printf(" bytes = %#010lx\n", (uint32) bytes);
return bytes;
fprintf(stderr, "Failed to read file: %s\n", strerror(
(status_t)bytes));
return (status_t)bytes;
} else {
// EOF
break;
@@ -64,25 +77,49 @@ status_t CopyFileData(BFile& dst, BFile& src)
}
status_t CopyAttributes(BNode& dst, BNode& src)
status_t
CopyAttributes(BNode& dst, BNode& src)
{
// copy attributes
src.RewindAttrs();
char name[B_ATTR_NAME_LENGTH];
while (src.GetNextAttrName(name) == B_OK) {
char attrName[B_ATTR_NAME_LENGTH];
while (src.GetNextAttrName(attrName) == B_OK) {
attr_info info;
if (src.GetAttrInfo(name, &info) == B_OK) {
size_t bufSize = info.size;
char* buf = new char[bufSize];
array_delete<char> bufDelete = buf;
// copy one attribute
ssize_t bytes = src.ReadAttr(name, info.type, 0, buf, bufSize);
if (bytes > 0) {
dst.WriteAttr(name, info.type, 0, buf, bufSize);
} else {
return bytes;
if (src.GetAttrInfo(attrName, &info) != B_OK) {
fprintf(stderr, "Failed to read info for attribute '%s'\n",
attrName);
continue;
}
// copy one attribute in chunks of 4096 bytes
size_t size = 4096;
uint8 buffer[size];
off_t offset = 0;
ssize_t read = src.ReadAttr(attrName, info.type, offset, buffer,
min_c(size, info.size));
if (read < 0) {
fprintf(stderr, "Error reading attribute '%s'\n", attrName);
return (status_t)read;
}
// NOTE: Attributes of size 0 are perfectly valid!
while (read >= 0) {
ssize_t written = dst.WriteAttr(attrName, info.type, offset, buffer,
read);
if (written != read) {
fprintf(stderr, "Error writing attribute '%s'\n", attrName);
if (written < 0)
return (status_t)written;
else
return B_IO_ERROR;
}
offset += read;
read = src.ReadAttr(attrName, info.type, offset, buffer,
min_c(size, info.size - offset));
if (read < 0) {
fprintf(stderr, "Error reading attribute '%s'\n", attrName);
return (status_t)read;
}
if (read == 0)
break;
}
}
@@ -90,7 +127,8 @@ status_t CopyAttributes(BNode& dst, BNode& src)
}
status_t CopyFile(BFile& dst, BFile& src)
status_t
CopyFile(BFile& dst, BFile& src)
{
status_t err = CopyFileData(dst, src);
if (err != B_OK)
+2
View File
@@ -2,6 +2,8 @@ SubDir HAIKU_TOP src apps soundrecorder ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders shared ;
Application SoundRecorder :
DrawButton.cpp
DrawingTidbits.cpp
@@ -43,7 +43,6 @@
#include "RecorderWindow.h"
#include "SoundConsumer.h"
#include "SoundListView.h"
#include "array_delete.h"
#include "FileUtils.h"
#if ! NDEBUG
+165 -202
View File
@@ -7,7 +7,9 @@
/ Copyright 1998-1999, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#include "SoundConsumer.h"
#include <new>
#include <stdio.h>
#include <OS.h>
@@ -15,9 +17,11 @@
#include <Buffer.h>
#include <TimeSource.h>
#include "AutoDeleter.h"
#include "SoundPrivate.h"
#include "SoundConsumer.h"
#include "array_delete.h"
using std::nothrow;
// If we don't mind the format changing to another format while
@@ -55,7 +59,8 @@ SoundConsumer::SoundConsumer(
BMediaNode(name ? name : "SoundConsumer"),
BBufferConsumer(B_MEDIA_RAW_AUDIO)
{
NODE(stderr, "SoundConsumer::SoundConsumer(%p, %p, %p, %p)\n", name, recordFunc, notifyFunc, cookie);
NODE(stderr, "SoundConsumer::SoundConsumer(%p, %p, %p, %p)\n", name,
recordFunc, notifyFunc, cookie);
if (!name) name = "SoundConsumer";
@@ -105,10 +110,8 @@ SoundConsumer::~SoundConsumer()
status_t
SoundConsumer::SetHooks(
SoundProcessFunc recordFunc,
SoundNotifyFunc notifyFunc,
void * cookie)
SoundConsumer::SetHooks(SoundProcessFunc recordFunc, SoundNotifyFunc notifyFunc,
void* cookie)
{
// SetHooks needs to be synchronized with the service thread, else we may
// call the wrong hook function with the wrong cookie, which would be bad.
@@ -134,31 +137,27 @@ SoundConsumer::SetHooks(
}
// Clean up.
delete_port(cmd.reply);
}
else {
// Within the service thread, it's OK to just go ahead and do the change.
} else {
// Within the service thread, it's OK to just go ahead and do the
// change.
DoHookChange(&cmd);
}
return err;
}
////////////////////////////////////////////////////////////////////////////////
//
// BMediaNode-derived methods
//
////////////////////////////////////////////////////////////////////////////////
// #pragma mark -BMediaNode-derived methods
port_id SoundConsumer::ControlPort() const
port_id
SoundConsumer::ControlPort() const
{
return m_port;
}
BMediaAddOn* SoundConsumer::AddOn(
int32 * internal_id) const
BMediaAddOn*
SoundConsumer::AddOn(int32 * internal_id) const
{
// This object is instantiated inside an application.
// Therefore, it has no add-on.
@@ -167,8 +166,8 @@ BMediaAddOn* SoundConsumer::AddOn(
}
void SoundConsumer::Start(
bigtime_t performance_time)
void
SoundConsumer::Start(bigtime_t performance_time)
{
// Since we are a consumer and just blindly accept buffers that are
// thrown at us, we don't need to do anything special in Start()/Stop().
@@ -180,18 +179,15 @@ void SoundConsumer::Start(
m_delta = performance_time - m_tmSeekTo;
m_seeking = false;
}
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_WILL_START, performance_time);
}
else {
else
Notify(B_WILL_START, performance_time);
}
}
void SoundConsumer::Stop(
bigtime_t performance_time,
bool immediate)
void
SoundConsumer::Stop(bigtime_t performance_time, bool immediate)
{
// Since we are a consumer and just blindly accept buffers that are
// thrown at us, we don't need to do anything special in Start()/Stop().
@@ -201,18 +197,15 @@ void SoundConsumer::Stop(
// it's a Node over which we have complete control, we can live with
// treating buffers received before the start time or after the stop
// time as any other buffer.
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_WILL_STOP, performance_time, immediate);
}
else {
else
Notify(B_WILL_STOP, performance_time, immediate);
}
}
void SoundConsumer::Seek(
bigtime_t media_time,
bigtime_t performance_time)
void
SoundConsumer::Seek(bigtime_t media_time, bigtime_t performance_time)
{
// Seek() on a consumer just serves to offset the time stamp
// of received buffers passed to our Record hook function.
@@ -220,20 +213,19 @@ void SoundConsumer::Seek(
// to disk or otherwise store them. You may also want to
// synchronize this node's media time with an upstream
// producer's media time to make this offset meaningful.
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_WILL_SEEK, performance_time, media_time);
}
else {
else
Notify(B_WILL_SEEK, performance_time, media_time);
}
m_tpSeekAt = performance_time;
m_tmSeekTo = media_time;
m_seeking = true;
}
void SoundConsumer::SetRunMode(
run_mode mode)
void
SoundConsumer::SetRunMode(run_mode mode)
{
if (mode == BMediaNode::B_OFFLINE) {
// BMediaNode::B_OFFLINE means we don't need to run in
@@ -241,8 +233,7 @@ void SoundConsumer::SetRunMode(
// thread.
int32 new_prio = suggest_thread_priority(B_OFFLINE_PROCESSING);
set_thread_priority(m_thread, new_prio);
}
else {
} else {
// We're running in real time, so we'd better have
// a big enough thread priority to handle it!
// Here's where those magic scheduler values
@@ -264,40 +255,39 @@ void SoundConsumer::SetRunMode(
// * The amount of time we spend processing is
// our ProcessingLatency().
bigtime_t period = 10000;
if (buffer_duration(m_input.format.u.raw_audio) > 0) {
if (buffer_duration(m_input.format.u.raw_audio) > 0)
period = buffer_duration(m_input.format.u.raw_audio);
}
// assuming we're running for 500 us or less per buffer
int32 new_prio = suggest_thread_priority(B_AUDIO_RECORDING,
period, period/2, ProcessingLatency());
period, period / 2, ProcessingLatency());
set_thread_priority(m_thread, new_prio);
}
}
void SoundConsumer::TimeWarp(
bigtime_t at_real_time,
bigtime_t to_performance_time)
void
SoundConsumer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
{
// Since buffers will come pre-time-stamped, we only need to look
// at them, so we can ignore the time warp as a consumer.
if (m_notifyHook) {
(*m_notifyHook)(m_cookie, B_WILL_TIMEWARP, at_real_time, to_performance_time);
}
else {
(*m_notifyHook)(m_cookie, B_WILL_TIMEWARP, at_real_time,
to_performance_time);
} else
Notify(B_WILL_TIMEWARP, at_real_time, to_performance_time);
}
}
void SoundConsumer::Preroll()
void
SoundConsumer::Preroll()
{
// There is nothing for us to do in Preroll()
}
void SoundConsumer::SetTimeSource(
BTimeSource * /* time_source */)
void
SoundConsumer::SetTimeSource(BTimeSource* /* time_source */)
{
// We don't need to do anything special to take note of the
// fact that the time source changed, because we get our timing
@@ -305,17 +295,14 @@ void SoundConsumer::SetTimeSource(
}
status_t SoundConsumer::HandleMessage(
int32 message,
const void * data,
size_t size)
status_t
SoundConsumer::HandleMessage(int32 message, const void* data, size_t size)
{
// Check with each of our superclasses to see if they
// understand the message. If none of them do, call
// BMediaNode::HandleBadMessage().
if ((BBufferConsumer::HandleMessage(message, data, size) < 0)
&& (BMediaNode::HandleMessage(message, data, size) < 0))
{
if (BBufferConsumer::HandleMessage(message, data, size) < 0
&& BMediaNode::HandleMessage(message, data, size) < 0) {
HandleBadMessage(message, data, size);
return B_ERROR;
}
@@ -323,33 +310,23 @@ status_t SoundConsumer::HandleMessage(
}
// #pragma mark - BBufferConsumer-derived methods
////////////////////////////////////////////////////////////////////////////////
//
// BBufferConsumer-derived methods
//
////////////////////////////////////////////////////////////////////////////////
status_t SoundConsumer::AcceptFormat(
const media_destination & dest,
media_format * format)
status_t
SoundConsumer::AcceptFormat(const media_destination& dest, media_format* format)
{
// We only accept formats aimed at our single input.
if (dest != m_input.destination) {
if (dest != m_input.destination)
return B_MEDIA_BAD_DESTINATION;
}
// If no format is specified, we say we want raw audio.
if (format->type <= 0) {
// If no format is specified, we say we want raw audio.
format->type = B_MEDIA_RAW_AUDIO;
format->u.raw_audio = media_raw_audio_format::wildcard;
}
// If a non-raw-audio format is specified, we tell the world what
// we want, and that the specified format was unacceptable to us.
else if (format->type != B_MEDIA_RAW_AUDIO) {
} else if (format->type != B_MEDIA_RAW_AUDIO) {
// If a non-raw-audio format is specified, we tell the world what
// we want, and that the specified format was unacceptable to us.
format->type = B_MEDIA_RAW_AUDIO;
format->u.raw_audio = media_raw_audio_format::wildcard;
return B_MEDIA_BAD_FORMAT;
@@ -368,14 +345,13 @@ status_t SoundConsumer::AcceptFormat(
}
status_t SoundConsumer::GetNextInput(
int32 * cookie,
media_input * out_input)
status_t
SoundConsumer::GetNextInput(int32* cookie, media_input* out_input)
{
NODE(stderr, "SoundConsumer: GetNextInput()\n");
// The "next" is kind of misleading, since it's also used for
// getting the first (and only) input.
if (!*cookie) {
if (*cookie == 0) {
if (m_input.source == media_source::null) {
// If there's no current connection, make sure we return a
// reasonable format telling the world we accept any raw audio.
@@ -394,16 +370,16 @@ status_t SoundConsumer::GetNextInput(
}
void SoundConsumer::DisposeInputCookie(
int32 /* cookie */)
void
SoundConsumer::DisposeInputCookie(int32 /* cookie */)
{
// We didn't allocate any memory or set any state in GetNextInput()
// so this function is a no-op.
}
void SoundConsumer::BufferReceived(
BBuffer * buffer)
void
SoundConsumer::BufferReceived(BBuffer* buffer)
{
NODE(stderr, "SoundConsumer::BufferReceived()\n");
// Whee, a buffer! Update the seek info, if necessary.
@@ -413,10 +389,12 @@ void SoundConsumer::BufferReceived(
}
// If there is a record hook, let the interested party have at it!
if (m_recordHook) {
(*m_recordHook)(m_cookie, buffer->Header()->start_time-m_delta, buffer->Data(), buffer->Header()->size_used, m_input.format.u.raw_audio);
}
else {
Record(buffer->Header()->start_time-m_delta, buffer->Data(), buffer->Header()->size_used, m_input.format.u.raw_audio);
(*m_recordHook)(m_cookie, buffer->Header()->start_time-m_delta,
buffer->Data(), buffer->Header()->size_used,
m_input.format.u.raw_audio);
} else {
Record(buffer->Header()->start_time-m_delta, buffer->Data(),
buffer->Header()->size_used, m_input.format.u.raw_audio);
}
// Buffers should ALWAYS be recycled, else whomever is producing them
// will starve.
@@ -424,33 +402,31 @@ void SoundConsumer::BufferReceived(
}
void SoundConsumer::ProducerDataStatus(
const media_destination & for_whom,
int32 status,
bigtime_t at_media_time)
void
SoundConsumer::ProducerDataStatus(const media_destination& for_whom,
int32 status, bigtime_t at_media_time)
{
if (for_whom == m_input.destination) {
// Tell whomever is interested that the upstream producer will or won't
// send more data in the immediate future.
if (m_notifyHook) {
(*m_notifyHook)(m_cookie, B_PRODUCER_DATA_STATUS, status, at_media_time);
}
else {
Notify(B_PRODUCER_DATA_STATUS, status, at_media_time);
}
}
if (for_whom != m_input.destination)
return;
// Tell whomever is interested that the upstream producer will or won't
// send more data in the immediate future.
if (m_notifyHook) {
(*m_notifyHook)(m_cookie, B_PRODUCER_DATA_STATUS, status,
at_media_time);
} else
Notify(B_PRODUCER_DATA_STATUS, status, at_media_time);
}
status_t SoundConsumer::GetLatencyFor(
const media_destination & for_whom,
bigtime_t * out_latency,
media_node_id * out_timesource)
status_t
SoundConsumer::GetLatencyFor(const media_destination& for_whom,
bigtime_t* out_latency, media_node_id* out_timesource)
{
// We only accept requests for the one-and-only input of our Node.
if (for_whom != m_input.destination) {
if (for_whom != m_input.destination)
return B_MEDIA_BAD_DESTINATION;
}
// Tell the world about our latency information (overridable by user).
*out_latency = TotalLatency();
*out_timesource = TimeSource()->Node().node;
@@ -458,32 +434,30 @@ status_t SoundConsumer::GetLatencyFor(
}
status_t SoundConsumer::Connected(
const media_source & producer,
const media_destination & where,
const media_format & with_format,
media_input * out_input)
status_t
SoundConsumer::Connected(const media_source& producer,
const media_destination& where, const media_format& with_format,
media_input* out_input)
{
NODE(stderr, "SoundConsumer::Connected()\n");
// Only accept connection requests when we're not already connected.
if (m_input.source != media_source::null) {
if (m_input.source != media_source::null)
return B_MEDIA_BAD_DESTINATION;
}
// Only accept connection requests on the one-and-only available input.
if (where != m_input.destination) {
if (where != m_input.destination)
return B_MEDIA_BAD_DESTINATION;
}
// Other than that, we accept pretty much anything. The format has been
// pre-cleared through AcceptFormat(), and we accept any format anyway.
m_input.source = producer;
m_input.format = with_format;
// Tell whomever is interested that there's now a connection.
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_CONNECTED, m_input.name);
}
else {
else
Notify(B_CONNECTED, m_input.name);
}
// This is the most important line -- return our connection information
// to the world so it can use it!
*out_input = m_input;
@@ -491,75 +465,69 @@ status_t SoundConsumer::Connected(
}
void SoundConsumer::Disconnected(
const media_source & producer,
const media_destination & where)
void
SoundConsumer::Disconnected(const media_source& producer,
const media_destination& where)
{
// We can't disconnect something which isn't us.
if (where != m_input.destination) {
if (where != m_input.destination)
return;
}
// We can't disconnect from someone who isn't connected to us.
if (producer != m_input.source) {
if (producer != m_input.source)
return;
}
// Tell the interested party that it's time to leave.
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_DISCONNECTED);
}
else {
else
Notify(B_DISCONNECTED);
}
// Mark ourselves as not-connected.
m_input.source = media_source::null;
}
status_t SoundConsumer::FormatChanged(
const media_source & producer,
const media_destination & consumer,
int32 from_change_count,
const media_format & format)
status_t
SoundConsumer::FormatChanged(const media_source& producer,
const media_destination& consumer, int32 from_change_count,
const media_format& format)
{
NODE(stderr, "SoundConsumer::Connected()\n");
// The up-stream guy feels like changing the format. If we can accept
// arbitrary format changes, we just say "OK". If, however, we're recording
// to a file, that's not such a good idea; we only accept format changes
// that are compatible with the format we're already using. You set this
// behaviour at compile time by defining ACCEPT_ANY_FORMAT_CHANGE to 1 or 0.
// behaviour at compile time by defining ACCEPT_ANY_FORMAT_CHANGE to 1 or
// 0.
status_t err = B_OK;
#if ACCEPT_ANY_FORMAT_CHANGE
media_format fmt(format);
err = AcceptFormat(m_input.destination, &fmt);
#else
if (m_input.source != media_source::null) {
err = format_is_compatible(format, m_input.format) ? B_OK : B_MEDIA_BAD_FORMAT;
err = format_is_compatible(format, m_input.format) ? B_OK
: B_MEDIA_BAD_FORMAT;
}
#endif
if (err >= B_OK) {
m_input.format = format;
if (m_notifyHook) {
(*m_notifyHook)(m_cookie, B_FORMAT_CHANGED, &m_input.format.u.raw_audio);
}
else {
(*m_notifyHook)(m_cookie, B_FORMAT_CHANGED,
&m_input.format.u.raw_audio);
} else
Notify(B_FORMAT_CHANGED, &m_input.format.u.raw_audio);
}
}
return err;
}
void
SoundConsumer::DoHookChange(
void * msg)
SoundConsumer::DoHookChange(void* msg)
{
// Tell the old guy we're changing the hooks ...
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_HOOKS_CHANGED);
}
else {
else
Notify(B_HOOKS_CHANGED);
}
// ... and then do it.
set_hooks_q * ptr = (set_hooks_q *)msg;
m_recordHook = ptr->process;
@@ -569,10 +537,10 @@ SoundConsumer::DoHookChange(
status_t
SoundConsumer::ThreadEntry(
void * obj)
SoundConsumer::ThreadEntry(void* cookie)
{
((SoundConsumer *)obj)->ServiceThread();
SoundConsumer* consumer = (SoundConsumer*)cookie;
consumer->ServiceThread();
return 0;
}
@@ -587,9 +555,11 @@ SoundConsumer::ServiceThread()
// A media kit message will never be bigger than B_MEDIA_MESSAGE_SIZE.
// Avoid wasing stack space by dynamically allocating at start.
char * msg = new char[B_MEDIA_MESSAGE_SIZE];
char* msg = new (nothrow) char[B_MEDIA_MESSAGE_SIZE];
if (msg == NULL)
return;
// Make sure we clean up this data when we exit the function.
array_delete<char> msg_delete(msg);
ArrayDeleter<char> _(msg);
int bad = 0;
while (true) {
// Call read_port_etc() with a timeout derived from a virtual function,
@@ -598,57 +568,50 @@ SoundConsumer::ServiceThread()
int32 code = 0;
status_t err = read_port_etc(m_port, &code, msg, B_MEDIA_MESSAGE_SIZE,
B_TIMEOUT, timeout);
MESSAGE(stderr, "SoundConsumer::ServiceThread() port %ld message %#010lx\n", m_port, code);
// If we received a message, err will be the size of the message (including 0).
if (err >= 0) {
MESSAGE(stderr, "SoundConsumer::ServiceThread() port %ld message "
"%#010lx\n", m_port, code);
// If we received a message, err will be the size of the message
// (including 0).
if (err >= B_OK) {
// Real messages reset the timeout time.
m_trTimeout = 0;
bad = 0;
// Check for our private stop message.
if (code == MSG_QUIT_NOW) {
if (m_notifyHook) {
// Check for our private stop message.
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_NODE_DIES, 0);
}
else {
else
Notify(B_NODE_DIES, 0);
}
break;
}
} else if (code == MSG_CHANGE_HOOKS) {
// Else check for our private change-hooks message.
else if (code == MSG_CHANGE_HOOKS) {
DoHookChange(msg);
// Write acknowledge to waiting thread.
write_port(((set_hooks_q *)msg)->reply, 0, 0, 0);
}
// Else it has to be a regular media kit message; go ahead and
// dispatch it.
else {
} else {
// Else it has to be a regular media kit message;
// go ahead and dispatch it.
HandleMessage(code, msg, err);
}
}
// Timing out means that there was no buffer. Tell the interested party.
else if (err == B_TIMED_OUT) {
if (m_notifyHook) {
} else if (err == B_TIMED_OUT) {
// Timing out means that there was no buffer. Tell the interested
// party.
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_OP_TIMED_OUT, timeout);
}
else {
else
Notify(B_OP_TIMED_OUT, timeout);
}
}
// Other errors are bad.
else {
} else {
// Other errors are bad.
FPRINTF(stderr, "SoundConsumer: error %#010lx\n", err);
bad++;
// If we receive three bad reads with no good messages inbetween,
// things are probably not going to improve (like the port disappeared
// or something) so we call it a day.
// things are probably not going to improve (like the port
// disappeared or something) so we call it a day.
if (bad > 3) {
if (m_notifyHook) {
if (m_notifyHook)
(*m_notifyHook)(m_cookie, B_NODE_DIES, bad, err, code, msg);
}
else {
else
Notify(B_NODE_DIES, bad, err, code, msg);
}
break;
}
}
@@ -664,8 +627,9 @@ SoundConsumer::Timeout()
// we've picked is to exponentially back off from one second and upwards.
// While it's true that 44 back-offs will run us out of precision in a
// bigtime_t, the time to actually reach 44 consecutive back-offs is longer
// than the expected market longevity of just about any piece of real estate.
// Is that the sound of an impending year-fifteen-million software problem? :-)
// than the expected market longevity of just about any piece of real
// estate. Is that the sound of an impending year-fifteen-million software
// problem? :-)
m_trTimeout = (m_trTimeout < 1000000) ? 1000000 : m_trTimeout*2;
return m_trTimeout;
}
@@ -689,12 +653,13 @@ SoundConsumer::TotalLatency()
return ProcessingLatency();
}
// #pragma mark -
void
SoundConsumer::Record(
bigtime_t /* time */,
const void * /* data */,
size_t /* size */,
const media_raw_audio_format & /* format */)
SoundConsumer::Record(bigtime_t /*time*/, const void* /*data*/,
size_t /*size*/, const media_raw_audio_format& /*format*/)
{
// If there is no record hook installed, we instead call this function
// for received buffers.
@@ -702,10 +667,8 @@ SoundConsumer::Record(
void
SoundConsumer::Notify(
int32 /* cause */,
...)
SoundConsumer::Notify(int32 /*cause*/, ...)
{
// If there is no notification hook installed, we instead call this function
// for giving notification of various events.
// If there is no notification hook installed, we instead call this
// function for giving notification of various events.
}
+100 -126
View File
@@ -7,13 +7,8 @@
/ Copyright 1998, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#if !defined( _SoundConsumer_h )
#define _SoundConsumer_h
#include <BufferConsumer.h>
#include "SoundUtils.h"
#ifndef SOUND_CONSUMER_H
#define SOUND_CONSUMER_H
// To use this Consumer:
// 1. Create Record and Notify hooks, or subclass SoundConsumer
@@ -33,141 +28,120 @@
// your Record function will see.
// 6: When you're done, disconnect the Consumer, then delete it.
class SoundConsumer :
public BBufferConsumer
{
public:
SoundConsumer(
const char * name,
SoundProcessFunc recordFunc = NULL,
SoundNotifyFunc notifyFunc = NULL,
void * cookie = NULL);
~SoundConsumer();
#include <BufferConsumer.h>
#include "SoundUtils.h"
// This function is OK to call from any thread.
status_t SetHooks(
SoundProcessFunc recordFunc = NULL,
SoundNotifyFunc notifyFunc = NULL,
void * cookie = NULL);
// The MediaNode interface
class SoundConsumer : public BBufferConsumer {
public:
virtual port_id ControlPort() const;
virtual BMediaAddOn* AddOn(
int32 * internal_id) const; /* Who instantiated you -- or NULL for app class */
SoundConsumer(const char* name,
SoundProcessFunc recordFunc = NULL,
SoundNotifyFunc notifyFunc = NULL,
void* cookie = NULL);
virtual ~SoundConsumer();
//This function is OK to call from any thread.
status_t SetHooks(SoundProcessFunc recordFunc = NULL,
SoundNotifyFunc notifyFunc = NULL,
void* cookie = NULL);
// The MediaNode interface
public:
virtual port_id ControlPort() const;
virtual BMediaAddOn* AddOn(int32* internalID) const;
// Who instantiated you -- or NULL for app class
protected:
virtual void Start(bigtime_t performanceTime);
virtual void Stop(bigtime_t performanceTime, bool immediate);
virtual void Seek(bigtime_t mediaTime,
bigtime_t performanceTime);
virtual void SetRunMode(run_mode mode);
virtual void TimeWarp(bigtime_t atRealTime,
bigtime_t to_performanceTime);
virtual void Preroll();
virtual void SetTimeSource(BTimeSource* timeSource);
virtual status_t HandleMessage(int32 message, const void* data,
size_t size);
virtual void Start(
bigtime_t performance_time);
virtual void Stop(
bigtime_t performance_time,
bool immediate);
virtual void Seek(
bigtime_t media_time,
bigtime_t performance_time);
virtual void SetRunMode(
run_mode mode);
virtual void TimeWarp(
bigtime_t at_real_time,
bigtime_t to_performance_time);
virtual void Preroll();
virtual void SetTimeSource(
BTimeSource * time_source);
virtual status_t HandleMessage(
int32 message,
const void * data,
size_t size);
// The BufferConsumer interface
virtual status_t AcceptFormat(
const media_destination & dest,
media_format * format);
virtual status_t GetNextInput( /* cookie starts at 0 */
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_media_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);
virtual void Disconnected(
const media_source & producer,
const media_destination & where);
virtual status_t FormatChanged(
const media_source & producer,
const media_destination & consumer,
int32 from_change_count,
const media_format & format);
// The BufferConsumer interface
virtual status_t AcceptFormat(const media_destination& dest,
media_format* format);
virtual status_t GetNextInput(int32* cookie,
media_input* _input);
virtual void DisposeInputCookie(int32 cookie);
virtual void BufferReceived(BBuffer* buffer);
virtual void ProducerDataStatus(
const media_destination& forWhom,
int32 status, bigtime_t atMediaTime);
virtual status_t GetLatencyFor(const media_destination& forWhom,
bigtime_t* _latency,
media_node_id* _timesource);
virtual status_t Connected(const media_source& producer,
const media_destination& where,
const media_format& format,
media_input* _input);
virtual void Disconnected(const media_source& producer,
const media_destination& where);
virtual status_t FormatChanged(const media_source& producer,
const media_destination& consumer,
int32 fromChangeCount,
const media_format& format);
protected:
// Functions called when no hooks are installed.
// OK to override instead of installing hooks.
virtual void Record(
bigtime_t time,
const void * data,
size_t size,
const media_raw_audio_format & format);
virtual void Notify(
int32 cause,
...);
// Functions called when no hooks are installed.
// OK to override instead of installing hooks.
virtual void Record(bigtime_t time, const void* data,
size_t size,
const media_raw_audio_format& format);
virtual void Notify(int32 cause, ...);
private:
SoundProcessFunc m_recordHook;
SoundNotifyFunc m_notifyHook;
void * m_cookie;
media_input m_input;
thread_id m_thread;
port_id m_port;
SoundProcessFunc m_recordHook;
SoundNotifyFunc m_notifyHook;
void* m_cookie;
media_input m_input;
thread_id m_thread;
port_id m_port;
// The times we need to deal with
// My notation for times: tr = real time,
// tp = performance time, tm = media time.
bigtime_t m_trTimeout; // how long to wait on the input port
bigtime_t m_tpSeekAt; // when we Seek
bigtime_t m_tmSeekTo; // target time for Seek
// The times we need to deal with
// My notation for times: tr = real time,
// tp = performance time, tm = media time.
bigtime_t m_trTimeout;
// how long to wait on the input port
bigtime_t m_tpSeekAt;
// when we Seek
bigtime_t m_tmSeekTo;
// target time for Seek
// The transformation from media to peformance time.
// d = p - m, so m + d = p.
// Media time is generally governed by the Seek
// function. In our node, we simply use media time as
// the time that we report to the record hook function.
// If we were a producer node, we might use media time
// to track where we were in playing a certain piece
// of media. But we aren't.
bigtime_t m_delta;
// The transformation from media to peformance time.
// d = p - m, so m + d = p.
// Media time is generally governed by the Seek
// function. In our node, we simply use media time as
// the time that we report to the record hook function.
// If we were a producer node, we might use media time
// to track where we were in playing a certain piece
// of media. But we aren't.
bigtime_t m_delta;
// State variables
bool m_seeking; // a Seek is pending
// State variables
bool m_seeking;
// a Seek is pending
// Functions to calculate timing values. OK to override.
// ProcessingLatency is the time it takes to process a buffer;
// TotalLatency is returned to producer; Timeout is passed
// to call to read_port_etc() in service thread loop.
virtual bigtime_t Timeout();
virtual bigtime_t ProcessingLatency();
virtual bigtime_t TotalLatency();
// The actual thread doing the work
static status_t ThreadEntry(
void * obj);
void ServiceThread();
void DoHookChange(
void * msg);
// Functions to calculate timing values. OK to override.
// ProcessingLatency is the time it takes to process a buffer;
// TotalLatency is returned to producer; Timeout is passed
// to call to read_port_etc() in service thread loop.
virtual bigtime_t Timeout();
virtual bigtime_t ProcessingLatency();
virtual bigtime_t TotalLatency();
// The actual thread doing the work
static status_t ThreadEntry(void* cookie);
void ServiceThread();
void DoHookChange(void* message);
};
#endif /* _SoundConsumer_h */
#endif // SOUND_CONSUMER_H
-30
View File
@@ -1,30 +0,0 @@
/*******************************************************************************
/
/ File: array_delete.h
/
/ Description: Template for deleting a new[] array of something.
/
/ Copyright 1998-1999, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#if !defined( _array_delete_h )
#define _array_delete_h
// Oooh! It's a template!
template<class C> class array_delete {
C * & m_ptr;
public:
// auto_ptr<> uses delete, not delete[], so we have to write our own.
// I like hanging on to a reference, because if we manually delete the
// array and set the pointer to NULL (or otherwise change the pointer)
// it will still work. Others like the more elaborate implementation
// of auto_ptr<>. Your Mileage May Vary.
array_delete(C * & ptr) : m_ptr(ptr) {}
~array_delete() { delete[] m_ptr; }
};
#endif /* array_delete_h */