BMediaRecorder: fix a few issues, fix style, remove unused SoundUtils

* Use the preferred time source (GetTimeSource) for the node
* Fix node releasing when creating the connection fails
* Add virtual slots and padding
* Refactor _Connect method
This commit is contained in:
Hamish Morrison 2015-01-09 20:56:32 +00:00
parent 739fd34cf5
commit 683cf2ff58
9 changed files with 164 additions and 362 deletions

View File

@ -6,16 +6,31 @@
#define _MEDIA_RECORDER_H
#include <MediaDefs.h>
#include <MediaNode.h>
#include <TimeSource.h>
#include "MediaRecorderNode.h"
#include "SoundUtils.h"
namespace BPrivate { namespace media {
class BMediaRecorderNode;
class BMediaRecorder {
public:
enum notification {
B_WILL_START = 1, // performance_time
B_WILL_STOP, // performance_time immediate
B_WILL_SEEK, // performance_time media_time
B_WILL_TIMEWARP, // real_time performance_time
};
typedef void (*ProcessFunc)(void* cookie,
bigtime_t timestamp, void* data,
size_t size, const media_format& format);
typedef void (*NotifyFunc)(void* cookie,
notification what, ...);
public:
BMediaRecorder(const char* name,
media_type type
@ -25,14 +40,6 @@ public:
status_t InitCheck() const;
typedef void (*ProcessFunc)(void* cookie,
bigtime_t timestamp, void* data,
size_t datasize,
const media_format& format);
typedef void (*NotifyFunc)(void* cookie,
int32 code, ...);
status_t SetHooks(ProcessFunc recordFunc = NULL,
NotifyFunc notifyFunc = NULL,
void* cookie = NULL);
@ -43,17 +50,14 @@ public:
virtual status_t Start(bool force = false);
virtual status_t Stop(bool force = false);
virtual status_t Connect(const media_format& format,
uint32 flags = 0);
virtual status_t Connect(const media_format& format);
virtual status_t Connect(const dormant_node_info& dormantInfo,
const media_format* format = NULL,
uint32 flags = 0);
const media_format& format);
virtual status_t Connect(const media_node& node,
const media_output* useOutput = NULL,
const media_format* format = NULL,
uint32 flags = 0);
const media_output* output = NULL,
const media_format* format = NULL);
virtual status_t Disconnect();
@ -67,37 +71,42 @@ public:
protected:
virtual void BufferReceived(void* buffer,
size_t size,
virtual void BufferReceived(void* buffer, size_t size,
const media_header& header);
private:
status_t _Connect(
const media_format* format,
uint32 flags,
const dormant_node_info* dormantNode,
const media_node* mediaNode,
const media_output* output);
status_t _Connect(const media_node& mediaNode,
const media_output* output,
const media_format& format);
status_t fInitErr;
virtual void _ReservedMediaRecorder0();
virtual void _ReservedMediaRecorder1();
virtual void _ReservedMediaRecorder2();
virtual void _ReservedMediaRecorder3();
virtual void _ReservedMediaRecorder4();
virtual void _ReservedMediaRecorder5();
virtual void _ReservedMediaRecorder6();
virtual void _ReservedMediaRecorder7();
bool fConnected;
bool fRunning;
status_t fInitErr;
BTimeSource* fTimeSource;
bool fConnected;
bool fRunning;
bool fReleaseOutputNode;
ProcessFunc fRecordHook;
NotifyFunc fNotifyHook;
ProcessFunc fRecordHook;
NotifyFunc fNotifyHook;
media_node fOutputNode;
media_output fOutput;
media_node fOutputNode;
media_output fOutput;
BMediaRecorderNode* fNode;
media_input fInput;
BMediaRecorderNode* fNode;
media_input fInput;
void* fBufferCookie;
void* fBufferCookie;
uint32 fPadding[32];
friend class BMediaRecorderNode;
friend class BMediaRecorderNode;
};
}

View File

@ -1,6 +1,6 @@
/*
* Copyright 1999, Be Incorporated
* Copyright 2014, Dario Casalinuovo
* Copyright 1999, Be Incorporated
* All Rights Reserved.
* This file may be used under the terms of the Be Sample Code License.
*/
@ -76,27 +76,23 @@ protected:
virtual void BufferReceived(BBuffer* buffer);
virtual void ProducerDataStatus(
const media_destination& forWhom,
const media_destination& destination,
int32 status,
bigtime_t performanceTime);
virtual status_t GetLatencyFor(
const media_destination& forWhom,
bigtime_t* outLatency,
media_node_id* outTimesource);
virtual status_t GetLatencyFor(const media_destination& destination,
bigtime_t* outLatency,
media_node_id* outTimesource);
virtual status_t Connected(
const media_source& producer,
virtual status_t Connected(const media_source& producer,
const media_destination& where,
const media_format& withFormat,
const media_format& format,
media_input* outInput);
virtual void Disconnected(
const media_source& producer,
virtual void Disconnected(const media_source& producer,
const media_destination& where);
virtual status_t FormatChanged(
const media_source& producer,
virtual status_t FormatChanged(const media_source& producer,
const media_destination& consumer,
int32 tag,
const media_format& format);

View File

@ -1,56 +0,0 @@
/*******************************************************************************
/
/ File: SoundUtils.h
/
/ Description: Utility functions for handling audio data.
/
/ Copyright 1998-1999, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#if ! defined( _SoundUtils_h )
#define _SoundUtils_h
#include <MediaDefs.h>
// Simple helper functions that come in handy when doing
// buffer calculations.
double us_to_s(bigtime_t usecs);
bigtime_t s_to_us(double secs);
int bytes_per_frame(const media_raw_audio_format & format);
int frames_per_buffer(const media_raw_audio_format & format);
bigtime_t buffer_duration(const media_raw_audio_format & format);
bigtime_t frames_duration(const media_raw_audio_format & format,
int64 num_frames);
int64 frames_for_duration(const media_raw_audio_format & format,
bigtime_t duration);
int buffers_for_duration(const media_raw_audio_format & format,
bigtime_t duration);
// This is a common hook function interface for
// SoundConsumer and SoundProducer to use.
typedef void (*SoundProcessFunc)(void * cookie,
bigtime_t timestamp, void * data, size_t datasize,
const media_raw_audio_format & format);
typedef void (*SoundNotifyFunc)(void * cookie,
int32 code, ...);
// These are special codes that we use in the Notify
// function hook.
enum {
B_WILL_START = 1, // performance_time
B_WILL_STOP, // performance_time immediate
B_WILL_SEEK, // performance_time media_time
B_WILL_TIMEWARP, // real_time performance_time
B_CONNECTED, // name (char*)
B_DISCONNECTED, //
B_FORMAT_CHANGED, // media_raw_audio_format*
B_NODE_DIES, // node will die!
B_HOOKS_CHANGED, //
B_OP_TIMED_OUT, // timeout that expired -- Consumer only
B_PRODUCER_DATA_STATUS, // status performance_time -- Consumer only
B_LATE_NOTICE // how_much performance_time -- Producer only
};
#endif /* _SoundUtils_h */

View File

@ -1,6 +1,6 @@
/*
* Copyright 2005, Jérôme Duval. All rights reserved.
* Copyright 2014, Dario Casalinuovo. All rights reserved.
* Copyright 2005, Jérôme Duval. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Inspired by SoundCapture from Be newsletter (Media Kit Basics:
@ -43,7 +43,6 @@
#include <TimeSource.h>
#include <NodeInfo.h>
#include "SoundUtils.h"
#include "RecorderWindow.h"
#include "FileUtils.h"
@ -1224,9 +1223,10 @@ RecorderWindow::RecordFile(void* cookie, bigtime_t timestamp,
void
RecorderWindow::NotifyRecordFile(void * cookie, int32 code, ...)
RecorderWindow::NotifyRecordFile(void * cookie,
BMediaRecorder::notification code, ...)
{
if ((code == B_WILL_STOP) || (code == B_NODE_DIES)) {
if (code == BMediaRecorder::B_WILL_STOP) {
RecorderWindow * window = (RecorderWindow *)cookie;
// Tell the window we've stopped, if it doesn't
// already know.

View File

@ -168,7 +168,7 @@ private:
void ErrorAlert(const char * action, status_t err);
static void RecordFile(void * cookie, bigtime_t timestamp, void * data, size_t size, const media_format & format);
static void NotifyRecordFile(void * cookie, int32 code, ...);
static void NotifyRecordFile(void * cookie, BMediaRecorder::notification code, ...);
static void PlayFile(void * cookie, void * data, size_t size, const media_raw_audio_format & format);
static void NotifyPlayFile(void * cookie, BSoundPlayer::sound_player_notification code, ...);

View File

@ -20,7 +20,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
# Private Media Kit
!missing_symbols.cpp
MediaRecorder.cpp
MediaRecorderNode.cpp
# Public Media Kit
Buffer.cpp
@ -58,6 +57,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
DefaultMediaTheme.cpp
DormantNodeManager.cpp
FormatManager.cpp
MediaRecorderNode.cpp
Notifications.cpp
request_data.cpp
SharedBufferList.cpp
@ -66,7 +66,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
TimeSourceObject.cpp
TimeSourceObjectManager.cpp
SoundPlayNode.cpp
SoundUtils.cpp
# Old (R3) Media Kit (built only for GCC2)
OldAudioModule.cpp

View File

@ -1,51 +1,20 @@
/*
* Copyright 1999, Be Incorporated
* Copyright 2015, Hamish Morrison <hamishm53@gmail.com>
* Copyright 2014, Dario Casalinuovo
* Copyright 1999, Be Incorporated
* All Rights Reserved.
* This file may be used under the terms of the Be Sample Code License.
*/
#include "MediaRecorder.h"
#include <MediaRecorder.h>
#include <MediaAddOn.h>
#include <MediaRoster.h>
#include <TimeSource.h>
#include "MediaDebug.h"
#include "MediaRecorderNode.h"
class MediaNodeReleaser {
public:
MediaNodeReleaser(media_node& mediaNode,
bool release = true)
:
fNode(mediaNode),
fRelease(release)
{
}
~MediaNodeReleaser()
{
if (fRelease)
BMediaRoster::Roster()->ReleaseNode(fNode);
}
void SetTo(media_node& node)
{
fNode = node;
}
void SetRelease(bool release)
{
fRelease = release;
}
private:
media_node& fNode;
bool fRelease;
};
#include <MediaDebug.h>
#include <MediaRecorderNode.h>
BMediaRecorder::BMediaRecorder(const char* name, media_type type)
@ -53,7 +22,7 @@ BMediaRecorder::BMediaRecorder(const char* name, media_type type)
fInitErr(B_OK),
fConnected(false),
fRunning(false),
fTimeSource(NULL),
fReleaseOutputNode(false),
fRecordHook(NULL),
fNotifyHook(NULL),
fNode(NULL),
@ -64,7 +33,10 @@ BMediaRecorder::BMediaRecorder(const char* name, media_type type)
BMediaRoster::Roster(&fInitErr);
if (fInitErr == B_OK) {
fNode = new BMediaRecorderNode(name, this, type);
fNode = new(std::nothrow) BMediaRecorderNode(name, this, type);
if (fNode == NULL)
fInitErr = B_NO_MEMORY;
fInitErr = BMediaRoster::CurrentRoster()->RegisterNode(fNode);
}
}
@ -79,10 +51,6 @@ BMediaRecorder::~BMediaRecorder()
Disconnect();
fNode->Release();
}
if (fTimeSource != NULL)
fTimeSource->Release();
}
@ -132,7 +100,7 @@ BMediaRecorder::BufferReceived(void* buffer, size_t size,
status_t
BMediaRecorder::Connect(const media_format& format, uint32 flags)
BMediaRecorder::Connect(const media_format& format)
{
CALLED();
@ -142,13 +110,42 @@ BMediaRecorder::Connect(const media_format& format, uint32 flags)
if (fConnected)
return B_MEDIA_ALREADY_CONNECTED;
return _Connect(&format, flags, NULL, NULL, NULL);
status_t err = B_OK;
media_node node;
switch (format.type) {
// switch on format for default
case B_MEDIA_RAW_AUDIO:
err = BMediaRoster::Roster()->GetAudioMixer(&node);
break;
case B_MEDIA_RAW_VIDEO:
case B_MEDIA_ENCODED_VIDEO:
err = BMediaRoster::Roster()->GetVideoInput(&node);
break;
// give up?
default:
return B_MEDIA_BAD_FORMAT;
}
if (err != B_OK)
return err;
fReleaseOutputNode = true;
err = _Connect(node, NULL, format);
if (err != B_OK) {
BMediaRoster::Roster()->ReleaseNode(node);
fReleaseOutputNode = false;
}
return err;
}
status_t
BMediaRecorder::Connect(const dormant_node_info& dormantInfo,
const media_format* format, uint32 flags)
BMediaRecorder::Connect(const dormant_node_info& dormantNode,
const media_format& format)
{
CALLED();
@ -158,14 +155,29 @@ BMediaRecorder::Connect(const dormant_node_info& dormantInfo,
if (fConnected)
return B_MEDIA_ALREADY_CONNECTED;
return _Connect(format, flags, &dormantInfo, NULL, NULL);
media_node node;
status_t err = BMediaRoster::Roster()->InstantiateDormantNode(dormantNode,
&node, B_FLAVOR_IS_GLOBAL);
if (err != B_OK)
return err;
fReleaseOutputNode = true;
err = _Connect(node, NULL, format);
if (err != B_OK) {
BMediaRoster::Roster()->ReleaseNode(node);
fReleaseOutputNode = false;
}
return err;
}
status_t
BMediaRecorder::Connect(const media_node& node,
const media_output* useOutput, const media_format* format,
uint32 flags)
const media_output* output, const media_format* format)
{
CALLED();
@ -175,7 +187,10 @@ BMediaRecorder::Connect(const media_node& node,
if (fConnected)
return B_MEDIA_ALREADY_CONNECTED;
return _Connect(format, flags, NULL, &node, useOutput);
if (format == NULL && output != NULL)
format = &output->format;
return _Connect(node, output, *format);
}
@ -206,11 +221,9 @@ BMediaRecorder::Disconnect()
fOutputNode.node, fOutput.source,
fNode->Node().node, fInput.destination);
BMediaRoster::Roster()->ReleaseNode(fOutputNode);
if (fTimeSource != NULL) {
fTimeSource->Release();
fTimeSource = NULL;
if (fReleaseOutputNode) {
BMediaRoster::Roster()->ReleaseNode(fOutputNode);
fReleaseOutputNode = false;
}
fConnected = false;
@ -240,12 +253,12 @@ BMediaRecorder::Start(bool force)
// start node here
status_t err = B_OK;
if (fNode->Node().kind & B_TIME_SOURCE)
if ((fOutputNode.kind & B_TIME_SOURCE) != 0)
err = BMediaRoster::CurrentRoster()->StartTimeSource(
fOutputNode, BTimeSource::RealTime());
else
err = BMediaRoster::CurrentRoster()->StartNode(
fOutputNode, fTimeSource->Now());
fOutputNode, fNode->TimeSource()->Now());
// then un-mute it
if (err == B_OK) {
@ -327,99 +340,42 @@ BMediaRecorder::Format() const
status_t
BMediaRecorder::_Connect(const media_format* format,
uint32 flags, const dormant_node_info* dormantNode,
const media_node* mediaNode, const media_output* output)
BMediaRecorder::_Connect(const media_node& node,
const media_output* output, const media_format& format)
{
CALLED();
status_t err = B_OK;
media_format ourFormat;
media_node node;
MediaNodeReleaser away(node, false);
media_format ourFormat = format;
media_output ourOutput;
// argument checking and set-up
if (format != NULL)
ourFormat = *format;
if (fNode == NULL)
return B_ERROR;
if (mediaNode == NULL && output != NULL)
return B_MISMATCHED_VALUES;
if (dormantNode != NULL && (mediaNode != NULL || output != NULL))
return B_MISMATCHED_VALUES;
if (format == NULL && output != NULL)
ourFormat = output->format;
fNode->SetAcceptedFormat(ourFormat);
// figure out the node to instantiate
if (dormantNode != NULL) {
err = BMediaRoster::Roster()->InstantiateDormantNode(
*dormantNode, &node, B_FLAVOR_IS_GLOBAL);
away.SetRelease(true);
} else if (mediaNode != NULL) {
node = *mediaNode;
} else {
switch (ourFormat.type) {
// switch on format for default
case B_MEDIA_RAW_AUDIO:
err = BMediaRoster::Roster()->GetAudioInput(&node);
away.SetRelease(true);
break;
case B_MEDIA_RAW_VIDEO:
case B_MEDIA_ENCODED_VIDEO:
err = BMediaRoster::Roster()->GetVideoInput(&node);
away.SetRelease(true);
break;
// give up?
default:
return B_MEDIA_BAD_FORMAT;
break;
}
}
fOutputNode = node;
// figure out the output provided
if (output != NULL) {
ourOutput = *output;
} else if (err == B_OK) {
media_output outputs[10];
int32 count = 10;
err = BMediaRoster::Roster()->GetFreeOutputsFor(node,
err = BMediaRoster::Roster()->GetFreeOutputsFor(fOutputNode,
outputs, count, &count, ourFormat.type);
if (err != B_OK)
return err;
err = B_MEDIA_BAD_SOURCE;
for (int i = 0; i < count; i++) {
if (format_is_compatible(outputs[i].format, ourFormat)) {
ourOutput = outputs[i];
err = B_OK;
ourFormat = outputs[i].format;
break;
}
}
} else {
return err;
}
if (ourOutput.source == media_source::null)
@ -427,30 +383,26 @@ BMediaRecorder::_Connect(const media_format* format,
// find our Node's free input
media_input ourInput;
err = fNode->GetInput(&ourInput);
if (err != B_OK)
return err;
media_node time_source;
if (node.kind & B_TIME_SOURCE)
time_source = node;
media_node timeSource;
if ((node.kind & B_TIME_SOURCE) != 0)
timeSource = node;
else
BMediaRoster::Roster()->GetSystemTimeSource(&time_source);
BMediaRoster::Roster()->GetTimeSource(&timeSource);
// set time source
BMediaRoster::Roster()->SetTimeSourceFor(
fNode->Node().node, time_source.node);
fTimeSource = BMediaRoster::CurrentRoster()->MakeTimeSourceFor(
fNode->Node());
err = BMediaRoster::Roster()->SetTimeSourceFor(fNode->Node().node,
timeSource.node);
if (err != B_OK)
return err;
// start the recorder node (it's always running)
err = BMediaRoster::CurrentRoster()->StartNode(
fOutputNode, fTimeSource->Now());
err = BMediaRoster::CurrentRoster()->StartNode(fOutputNode,
fNode->TimeSource()->Now());
if (err != B_OK)
return err;
@ -467,7 +419,16 @@ BMediaRecorder::_Connect(const media_format* format,
return err;
fConnected = true;
away.SetRelease(false);
return err;
return B_OK;
}
void BMediaRecorder::_ReservedMediaRecorder0() { }
void BMediaRecorder::_ReservedMediaRecorder1() { }
void BMediaRecorder::_ReservedMediaRecorder2() { }
void BMediaRecorder::_ReservedMediaRecorder3() { }
void BMediaRecorder::_ReservedMediaRecorder4() { }
void BMediaRecorder::_ReservedMediaRecorder5() { }
void BMediaRecorder::_ReservedMediaRecorder6() { }
void BMediaRecorder::_ReservedMediaRecorder7() { }

View File

@ -1,6 +1,6 @@
/*
* Copyright 1999, Be Incorporated
* Copyright 2014, Dario Casalinuovo
* Copyright 1999, Be Incorporated
* All Rights Reserved.
* This file may be used under the terms of the Be Sample Code License.
*/
@ -13,8 +13,8 @@
#include <TimedEventQueue.h>
#include <TimeSource.h>
#include "MediaDebug.h"
#include "MediaRecorder.h"
#include <MediaDebug.h>
#include <MediaRecorder.h>
BMediaRecorderNode::BMediaRecorderNode(const char* name,
@ -146,7 +146,7 @@ BMediaRecorderNode::Start(bigtime_t performanceTime)
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
B_WILL_START, performanceTime);
BMediaRecorder::B_WILL_START, performanceTime);
fRecorder->fRunning = true;
}
@ -159,7 +159,7 @@ BMediaRecorderNode::Stop(bigtime_t performanceTime, bool immediate)
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
B_WILL_STOP, performanceTime, immediate);
BMediaRecorder::B_WILL_STOP, performanceTime, immediate);
fRecorder->fRunning = false;
}
@ -172,7 +172,7 @@ BMediaRecorderNode::Seek(bigtime_t mediaTime, bigtime_t performanceTime)
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
B_WILL_SEEK, performanceTime, mediaTime);
BMediaRecorder::B_WILL_SEEK, performanceTime, mediaTime);
}
@ -185,7 +185,7 @@ BMediaRecorderNode::TimeWarp(bigtime_t realTime, bigtime_t performanceTime)
// at them, so we can ignore the time warp as a consumer.
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
B_WILL_TIMEWARP, realTime, performanceTime);
BMediaRecorder::B_WILL_TIMEWARP, realTime, performanceTime);
}

View File

@ -1,107 +0,0 @@
/******************************************************************************
/
/ File: SoundUtils.cpp
/
/ Description: Utility functions for handling audio data.
/
/ Copyright 1998-1999, Be Incorporated, All Rights Reserved
/
******************************************************************************/
#include <math.h>
#include "SoundUtils.h"
// These two conversions seem to pop up all the time in media code.
// I guess it's the curse of microsecond resolution... ;-)
double
us_to_s(bigtime_t usecs)
{
return (usecs / 1000000.0);
}
bigtime_t
s_to_us(double secs)
{
return (bigtime_t) (secs * 1000000.0);
}
int
bytes_per_frame(
const media_raw_audio_format & format)
{
// The media_raw_audio_format format constants encode the
// bytes-per-sample value in the low nybble. Having a fixed
// number of bytes-per-sample, and no inter-sample relationships,
// is what makes a format "raw".
int bytesPerSample = format.format & 0xf;
return bytesPerSample * format.channel_count;
}
int
frames_per_buffer(
const media_raw_audio_format & format)
{
// This will give us the number of full-sized frames that will fit
// in a buffer. (Remember, integer division automatically rounds
// down.)
int frames = 0;
if (bytes_per_frame(format) > 0) {
frames = format.buffer_size / bytes_per_frame(format);
}
return frames;
}
bigtime_t
buffer_duration(
const media_raw_audio_format & format)
{
// Figuring out duration is easy. We take extra precaution to
// not divide by zero or return irrelevant results.
bigtime_t duration = 0;
if (format.buffer_size > 0 && format.frame_rate > 0
&& bytes_per_frame(format) > 0) {
// In these kinds of calculations, it's always useful to double-check
// the unit conversions. (Anyone remember high school physics?)
// bytes/(bytes/frame) / frames/sec
// = frames * sec/frames
// = secs which is what we want.
duration = s_to_us((format.buffer_size / bytes_per_frame(format))
/ format.frame_rate);
}
return duration;
}
bigtime_t
frames_duration(
const media_raw_audio_format & format, int64 num_frames)
{
// Tells us how long in us it will take to produce num_frames,
// with the given format.
bigtime_t duration = 0;
if (format.frame_rate > 0) {
duration = s_to_us(num_frames/format.frame_rate);
}
return duration;
}
int
buffers_for_duration(
const media_raw_audio_format & format, bigtime_t duration)
{
// Double-checking those unit conversions again:
// secs * ( (frames/sec) / (frames/buffer) ) = secs * (buffers/sec)
// = buffers
int buffers = 0;
if (frames_per_buffer(format) > 0) {
buffers = (int) ceil(us_to_s(duration)
*(format.frame_rate/frames_per_buffer(format)));
}
return buffers;
}
int64
frames_for_duration(
const media_raw_audio_format & format, bigtime_t duration)
{
return (int64) ceil(format.frame_rate*us_to_s(duration));
}