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