All sorts of refactoring with regards to the audio node and format setup. At
first I tried adding support for changing the format during running the node connection, but later found out that this is not implemented in the system mixer (it has this weird setting to allow input format changes, but if you do this, the media_server will just crash, since the backend does not support it yet). Also, the Media Kit documentation is extremely lacking in this regard. I ended up re-establishing the node connection when the audio format is supposed to change, just like it is already done for video. This means that audio files now play with their native channel count and frame rate. But it isn't so well tested yet, if 48 kHz for example introduce some clicks. The channel count should not be a problem though, I've also tested that with some movies and it works fine. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33678 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -295,7 +295,7 @@ Controller::SetTo(const PlaylistItemRef& item)
|
|||||||
int height;
|
int height;
|
||||||
GetSize(&width, &height);
|
GetSize(&width, &height);
|
||||||
color_space preferredVideoFormat = B_NO_COLOR_SPACE;
|
color_space preferredVideoFormat = B_NO_COLOR_SPACE;
|
||||||
if (fVideoTrackSupplier) {
|
if (fVideoTrackSupplier != NULL) {
|
||||||
const media_format& format = fVideoTrackSupplier->Format();
|
const media_format& format = fVideoTrackSupplier->Format();
|
||||||
preferredVideoFormat = format.u.raw_video.display.format;
|
preferredVideoFormat = format.u.raw_video.display.format;
|
||||||
}
|
}
|
||||||
@@ -308,13 +308,22 @@ Controller::SetTo(const PlaylistItemRef& item)
|
|||||||
else
|
else
|
||||||
enabledNodes = AUDIO_AND_VIDEO;
|
enabledNodes = AUDIO_AND_VIDEO;
|
||||||
|
|
||||||
|
float audioFrameRate = 44100.0f;
|
||||||
|
uint32 audioChannels = 2;
|
||||||
|
if (fAudioTrackSupplier != NULL) {
|
||||||
|
const media_format& audioTrackFormat = fAudioTrackSupplier->Format();
|
||||||
|
audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate;
|
||||||
|
audioChannels = audioTrackFormat.u.raw_audio.channel_count;
|
||||||
|
}
|
||||||
|
|
||||||
if (InitCheck() != B_OK) {
|
if (InitCheck() != B_OK) {
|
||||||
Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
|
Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
|
||||||
preferredVideoFormat, LOOPING_ALL, false, 1.0, enabledNodes,
|
preferredVideoFormat, audioFrameRate, audioChannels, LOOPING_ALL,
|
||||||
useOverlays);
|
false, 1.0, enabledNodes, useOverlays);
|
||||||
} else {
|
} else {
|
||||||
FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
|
FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
|
||||||
preferredVideoFormat, enabledNodes, useOverlays);
|
preferredVideoFormat, audioFrameRate, audioChannels, enabledNodes,
|
||||||
|
useOverlays);
|
||||||
}
|
}
|
||||||
|
|
||||||
_NotifyFileChanged();
|
_NotifyFileChanged();
|
||||||
|
|||||||
@@ -66,8 +66,9 @@ NodeManager::~NodeManager()
|
|||||||
// Init
|
// Init
|
||||||
status_t
|
status_t
|
||||||
NodeManager::Init(BRect videoBounds, float videoFrameRate,
|
NodeManager::Init(BRect videoBounds, float videoFrameRate,
|
||||||
color_space preferredVideoFormat, int32 loopingMode,
|
color_space preferredVideoFormat, float audioFrameRate,
|
||||||
bool loopingEnabled, float speed, uint32 enabledNodes, bool useOverlays)
|
uint32 audioChannels, int32 loopingMode, bool loopingEnabled,
|
||||||
|
float speed, uint32 enabledNodes, bool useOverlays)
|
||||||
{
|
{
|
||||||
// init base class
|
// init base class
|
||||||
PlaybackManager::Init(videoFrameRate, loopingMode, loopingEnabled, speed);
|
PlaybackManager::Init(videoFrameRate, loopingMode, loopingEnabled, speed);
|
||||||
@@ -83,7 +84,7 @@ NodeManager::Init(BRect videoBounds, float videoFrameRate,
|
|||||||
fAudioSupplier = CreateAudioSupplier();
|
fAudioSupplier = CreateAudioSupplier();
|
||||||
|
|
||||||
return FormatChanged(videoBounds, videoFrameRate, preferredVideoFormat,
|
return FormatChanged(videoBounds, videoFrameRate, preferredVideoFormat,
|
||||||
enabledNodes, useOverlays, true);
|
audioFrameRate, audioChannels, enabledNodes, useOverlays, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitCheck
|
// InitCheck
|
||||||
@@ -118,8 +119,8 @@ NodeManager::CleanupNodes()
|
|||||||
// FormatChanged
|
// FormatChanged
|
||||||
status_t
|
status_t
|
||||||
NodeManager::FormatChanged(BRect videoBounds, float videoFrameRate,
|
NodeManager::FormatChanged(BRect videoBounds, float videoFrameRate,
|
||||||
color_space preferredVideoFormat, uint32 enabledNodes, bool useOverlays,
|
color_space preferredVideoFormat, float audioFrameRate,
|
||||||
bool force)
|
uint32 audioChannels, uint32 enabledNodes, bool useOverlays, bool force)
|
||||||
{
|
{
|
||||||
TRACE("NodeManager::FormatChanged()\n");
|
TRACE("NodeManager::FormatChanged()\n");
|
||||||
|
|
||||||
@@ -144,7 +145,7 @@ NodeManager::FormatChanged(BRect videoBounds, float videoFrameRate,
|
|||||||
SetVideoBounds(videoBounds);
|
SetVideoBounds(videoBounds);
|
||||||
|
|
||||||
status_t ret = _SetUpNodes(preferredVideoFormat, enabledNodes,
|
status_t ret = _SetUpNodes(preferredVideoFormat, enabledNodes,
|
||||||
useOverlays);
|
useOverlays, audioFrameRate, audioChannels);
|
||||||
if (ret == B_OK)
|
if (ret == B_OK)
|
||||||
_StartNodes();
|
_StartNodes();
|
||||||
else
|
else
|
||||||
@@ -253,7 +254,7 @@ NodeManager::SetPeakListener(BHandler* handler)
|
|||||||
// _SetUpNodes
|
// _SetUpNodes
|
||||||
status_t
|
status_t
|
||||||
NodeManager::_SetUpNodes(color_space preferredVideoFormat, uint32 enabledNodes,
|
NodeManager::_SetUpNodes(color_space preferredVideoFormat, uint32 enabledNodes,
|
||||||
bool useOverlays)
|
bool useOverlays, float audioFrameRate, uint32 audioChannels)
|
||||||
{
|
{
|
||||||
TRACE("NodeManager::_SetUpNodes()\n");
|
TRACE("NodeManager::_SetUpNodes()\n");
|
||||||
|
|
||||||
@@ -289,7 +290,7 @@ NodeManager::_SetUpNodes(color_space preferredVideoFormat, uint32 enabledNodes,
|
|||||||
|
|
||||||
// setup the audio nodes
|
// setup the audio nodes
|
||||||
if (enabledNodes != VIDEO_ONLY) {
|
if (enabledNodes != VIDEO_ONLY) {
|
||||||
fStatus = _SetUpAudioNodes();
|
fStatus = _SetUpAudioNodes(audioFrameRate, audioChannels);
|
||||||
if (fStatus != B_OK) {
|
if (fStatus != B_OK) {
|
||||||
print_error("Error setting up audio nodes", fStatus);
|
print_error("Error setting up audio nodes", fStatus);
|
||||||
fMediaRoster->Unlock();
|
fMediaRoster->Unlock();
|
||||||
@@ -445,7 +446,7 @@ NodeManager::_SetUpVideoNodes(color_space preferredVideoFormat,
|
|||||||
|
|
||||||
// _SetUpAudioNodes
|
// _SetUpAudioNodes
|
||||||
status_t
|
status_t
|
||||||
NodeManager::_SetUpAudioNodes()
|
NodeManager::_SetUpAudioNodes(float audioFrameRate, uint32 audioChannels)
|
||||||
{
|
{
|
||||||
fAudioProducer = new AudioProducer("MediaPlayer Audio Out", fAudioSupplier);
|
fAudioProducer = new AudioProducer("MediaPlayer Audio Out", fAudioSupplier);
|
||||||
fAudioProducer->SetPeakListener(fPeakListener);
|
fAudioProducer->SetPeakListener(fPeakListener);
|
||||||
@@ -489,11 +490,13 @@ NodeManager::_SetUpAudioNodes()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// got the endpoints; now we connect it!
|
// got the endpoints; now we connect it!
|
||||||
media_format audio_format;
|
media_format audioFormat;
|
||||||
audio_format.type = B_MEDIA_RAW_AUDIO;
|
audioFormat.type = B_MEDIA_RAW_AUDIO;
|
||||||
audio_format.u.raw_audio = media_raw_audio_format::wildcard;
|
audioFormat.u.raw_audio = media_raw_audio_format::wildcard;
|
||||||
|
audioFormat.u.raw_audio.frame_rate = audioFrameRate;
|
||||||
|
audioFormat.u.raw_audio.channel_count = audioChannels;
|
||||||
fStatus = fMediaRoster->Connect(soundOutput.source, mixerInput.destination,
|
fStatus = fMediaRoster->Connect(soundOutput.source, mixerInput.destination,
|
||||||
&audio_format, &soundOutput, &mixerInput);
|
&audioFormat, &soundOutput, &mixerInput);
|
||||||
if (fStatus != B_OK) {
|
if (fStatus != B_OK) {
|
||||||
print_error("unable to connect audio nodes", fStatus);
|
print_error("unable to connect audio nodes", fStatus);
|
||||||
return fStatus;
|
return fStatus;
|
||||||
@@ -502,7 +505,7 @@ NodeManager::_SetUpAudioNodes()
|
|||||||
// the inputs and outputs might have been reassigned during the
|
// the inputs and outputs might have been reassigned during the
|
||||||
// nodes' negotiation of the Connect(). That's why we wait until
|
// nodes' negotiation of the Connect(). That's why we wait until
|
||||||
// after Connect() finishes to save their contents.
|
// after Connect() finishes to save their contents.
|
||||||
fAudioConnection.format = audio_format;
|
fAudioConnection.format = audioFormat;
|
||||||
fAudioConnection.source = soundOutput.source;
|
fAudioConnection.source = soundOutput.source;
|
||||||
fAudioConnection.destination = mixerInput.destination;
|
fAudioConnection.destination = mixerInput.destination;
|
||||||
fAudioConnection.connected = true;
|
fAudioConnection.connected = true;
|
||||||
@@ -694,7 +697,6 @@ printf("performance time for %lld: %lld\n", real + latency
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fAudioProducer) {
|
if (fAudioProducer) {
|
||||||
fAudioProducer->SetRunning(true);
|
|
||||||
status = fMediaRoster->StartNode(fAudioConnection.producer, perf);
|
status = fMediaRoster->StartNode(fAudioConnection.producer, perf);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
print_error("Can't start the audio producer", status);
|
print_error("Can't start the audio producer", status);
|
||||||
@@ -715,27 +717,19 @@ void
|
|||||||
NodeManager::_StopNodes()
|
NodeManager::_StopNodes()
|
||||||
{
|
{
|
||||||
TRACE("NodeManager::_StopNodes()\n");
|
TRACE("NodeManager::_StopNodes()\n");
|
||||||
// if (PlayMode() == MODE_PLAYING_PAUSED_FORWARD
|
|
||||||
// || PlayMode() == MODE_PLAYING_PAUSED_FORWARD)
|
|
||||||
// return;
|
|
||||||
fMediaRoster = BMediaRoster::Roster();
|
fMediaRoster = BMediaRoster::Roster();
|
||||||
if (!fMediaRoster) {
|
if (fMediaRoster != NULL && fMediaRoster->Lock()) {
|
||||||
if (fAudioProducer)
|
|
||||||
fAudioProducer->SetRunning(false);
|
|
||||||
return;
|
|
||||||
} else if (fMediaRoster->Lock()) {
|
|
||||||
// begin mucking with the media roster
|
// begin mucking with the media roster
|
||||||
if (fVideoProducer) {
|
if (fVideoProducer != NULL) {
|
||||||
TRACE(" stopping video producer...\n");
|
TRACE(" stopping video producer...\n");
|
||||||
fMediaRoster->StopNode(fVideoConnection.producer, 0, true);
|
fMediaRoster->StopNode(fVideoConnection.producer, 0, true);
|
||||||
}
|
}
|
||||||
if (fAudioProducer) {
|
if (fAudioProducer != NULL) {
|
||||||
TRACE(" stopping audio producer...\n");
|
TRACE(" stopping audio producer...\n");
|
||||||
fAudioProducer->SetRunning(false);
|
|
||||||
fMediaRoster->StopNode(fAudioConnection.producer, 0, true);
|
fMediaRoster->StopNode(fAudioConnection.producer, 0, true);
|
||||||
// synchronous stop
|
// synchronous stop
|
||||||
}
|
}
|
||||||
if (fVideoConsumer) {
|
if (fVideoConsumer != NULL) {
|
||||||
TRACE(" stopping video consumer...\n");
|
TRACE(" stopping video consumer...\n");
|
||||||
fMediaRoster->StopNode(fVideoConnection.consumer, 0, true);
|
fMediaRoster->StopNode(fVideoConnection.consumer, 0, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,10 +40,9 @@ class NodeManager : public PlaybackManager {
|
|||||||
|
|
||||||
status_t Init(BRect videoBounds, float videoFrameRate,
|
status_t Init(BRect videoBounds, float videoFrameRate,
|
||||||
color_space preferredVideoFormat,
|
color_space preferredVideoFormat,
|
||||||
int32 loopingMode,
|
float audioFrameRate, uint32 audioChannels,
|
||||||
bool loopingEnabled,
|
int32 loopingMode, bool loopingEnabled,
|
||||||
float speed,
|
float speed, uint32 enabledNodes,
|
||||||
uint32 enabledNodes,
|
|
||||||
bool useOverlays);
|
bool useOverlays);
|
||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
// only call this if the
|
// only call this if the
|
||||||
@@ -53,9 +52,11 @@ class NodeManager : public PlaybackManager {
|
|||||||
status_t FormatChanged(BRect videoBounds,
|
status_t FormatChanged(BRect videoBounds,
|
||||||
float videoFrameRate,
|
float videoFrameRate,
|
||||||
color_space preferredVideoFormat,
|
color_space preferredVideoFormat,
|
||||||
|
float audioFrameRate, uint32 audioChannels,
|
||||||
uint32 enabledNodes,
|
uint32 enabledNodes,
|
||||||
bool useOverlays,
|
bool useOverlays,
|
||||||
bool force = false);
|
bool force = false);
|
||||||
|
|
||||||
virtual void SetPlayMode(int32 mode,
|
virtual void SetPlayMode(int32 mode,
|
||||||
bool continuePlaying = true);
|
bool continuePlaying = true);
|
||||||
|
|
||||||
@@ -76,11 +77,14 @@ class NodeManager : public PlaybackManager {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _SetUpNodes(color_space preferredVideoFormat,
|
status_t _SetUpNodes(color_space preferredVideoFormat,
|
||||||
uint32 enabledNodes, bool useOverlays);
|
uint32 enabledNodes, bool useOverlays,
|
||||||
|
float audioFrameRate,
|
||||||
|
uint32 audioChannels);
|
||||||
status_t _SetUpVideoNodes(
|
status_t _SetUpVideoNodes(
|
||||||
color_space preferredVideoFormat,
|
color_space preferredVideoFormat,
|
||||||
bool useOverlays);
|
bool useOverlays);
|
||||||
status_t _SetUpAudioNodes();
|
status_t _SetUpAudioNodes(float audioFrameRate,
|
||||||
|
uint32 audioChannels);
|
||||||
status_t _TearDownNodes(bool disconnect = true);
|
status_t _TearDownNodes(bool disconnect = true);
|
||||||
status_t _StartNodes();
|
status_t _StartNodes();
|
||||||
void _StopNodes();
|
void _StopNodes();
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ AudioAdapter::AudioAdapter(AudioReader* source, const media_format& format)
|
|||||||
|
|
||||||
if (fFormat.u.raw_audio.channel_count
|
if (fFormat.u.raw_audio.channel_count
|
||||||
!= source->Format().u.raw_audio.channel_count) {
|
!= source->Format().u.raw_audio.channel_count) {
|
||||||
TRACE("AudioAdapter() - using channel converter\n");
|
TRACE("AudioAdapter() - using channel converter (%ld -> %ld)\n",
|
||||||
|
source->Format().u.raw_audio.channel_count,
|
||||||
|
fFormat.u.raw_audio.channel_count);
|
||||||
fChannelConverter = new (nothrow) AudioChannelConverter(source,
|
fChannelConverter = new (nothrow) AudioChannelConverter(source,
|
||||||
fFormat);
|
fFormat);
|
||||||
source = fChannelConverter;
|
source = fChannelConverter;
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels,
|
|||||||
{
|
{
|
||||||
// TODO: more conversions!
|
// TODO: more conversions!
|
||||||
switch (inChannels) {
|
switch (inChannels) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
switch (outChannels) {
|
switch (outChannels) {
|
||||||
case 2:
|
case 2:
|
||||||
@@ -61,13 +63,13 @@ convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
default:
|
||||||
switch (outChannels) {
|
switch (outChannels) {
|
||||||
case 2:
|
case 2:
|
||||||
for (int32 i = 0; i < frames; i++) {
|
for (int32 i = 0; i < frames; i++) {
|
||||||
outBuffer[0] = inBuffer[0];
|
outBuffer[0] = inBuffer[0];
|
||||||
outBuffer[1] = inBuffer[1];
|
outBuffer[1] = inBuffer[1];
|
||||||
inBuffer += 5;
|
inBuffer += outChannels;
|
||||||
outBuffer += 2;
|
outBuffer += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
/* Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
|
/*
|
||||||
* Distributed under the terms of the Be Sample Code license.
|
* Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
|
||||||
|
* Distributed under the terms of the Be Sample Code license.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>,
|
* Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>,
|
||||||
* Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>,
|
* Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>,
|
||||||
* All Rights Reserved. Distributed under the terms of the MIT license.
|
* All Rights Reserved. Distributed under the terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AudioProducer.h"
|
#include "AudioProducer.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -32,13 +34,15 @@
|
|||||||
|
|
||||||
|
|
||||||
// debugging
|
// debugging
|
||||||
//#define TRACE_AUDIO_PRODUCER
|
#define TRACE_AUDIO_PRODUCER
|
||||||
#ifdef TRACE_AUDIO_PRODUCER
|
#ifdef TRACE_AUDIO_PRODUCER
|
||||||
# define TRACE(x...) printf(x)
|
# define TRACE(x...) printf(x)
|
||||||
# define ERROR(x...) fprintf(stderr, x)
|
# define TRACE_BUFFER(x...)
|
||||||
|
# define ERROR(x...) fprintf(stderr, x)
|
||||||
#else
|
#else
|
||||||
# define TRACE(x...)
|
# define TRACE(x...)
|
||||||
# define ERROR(x...) fprintf(stderr, x)
|
# define TRACE_BUFFER(x...)
|
||||||
|
# define ERROR(x...) fprintf(stderr, x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -96,7 +100,6 @@ AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
|
|||||||
fFramesSent(0),
|
fFramesSent(0),
|
||||||
fStartTime(0),
|
fStartTime(0),
|
||||||
fSupplier(supplier),
|
fSupplier(supplier),
|
||||||
fRunning(false),
|
|
||||||
|
|
||||||
fPeakListener(NULL)
|
fPeakListener(NULL)
|
||||||
{
|
{
|
||||||
@@ -175,15 +178,12 @@ AudioProducer::FormatSuggestionRequested(media_type type, int32 quality,
|
|||||||
if (!_format)
|
if (!_format)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// this is the format we'll be returning (our preferred format)
|
// This is the format we'll be returning (our preferred format)
|
||||||
*_format = fPreferredFormat;
|
*_format = fPreferredFormat;
|
||||||
|
|
||||||
// a wildcard type is okay; we can specialize it
|
// A wildcard type is okay; we can specialize it, otherwise only raw audio
|
||||||
if (type == B_MEDIA_UNKNOWN_TYPE)
|
// is supported
|
||||||
type = B_MEDIA_RAW_AUDIO;
|
if (type != B_MEDIA_UNKNOWN_TYPE && type != B_MEDIA_RAW_AUDIO)
|
||||||
|
|
||||||
// we only support raw audio
|
|
||||||
if (type != B_MEDIA_RAW_AUDIO)
|
|
||||||
return B_MEDIA_BAD_FORMAT;
|
return B_MEDIA_BAD_FORMAT;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -200,20 +200,28 @@ AudioProducer::FormatProposal(const media_source& output, media_format* format)
|
|||||||
return B_MEDIA_BAD_SOURCE;
|
return B_MEDIA_BAD_SOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we might want to support different audio formats
|
// Raw audio or wildcard type, either is okay by us. If the format is
|
||||||
// we only support floating-point raw audio, so we always return that, but
|
// anything else, overwrite it with our preferred format. Also, we only support
|
||||||
// we supply an error code depending on whether we found the proposal
|
// floating point audio in the host native byte order at the moment.
|
||||||
// acceptable.
|
if ((format->type != B_MEDIA_UNKNOWN_TYPE
|
||||||
media_type requestedType = format->type;
|
&& format->type != B_MEDIA_RAW_AUDIO)
|
||||||
*format = fPreferredFormat;
|
|| (format->u.raw_audio.format
|
||||||
|
!= media_raw_audio_format::wildcard.format
|
||||||
// raw audio or wildcard type, either is okay by us
|
&& format->u.raw_audio.format
|
||||||
if (requestedType != B_MEDIA_UNKNOWN_TYPE
|
!= fPreferredFormat.u.raw_audio.format)
|
||||||
&& requestedType != B_MEDIA_RAW_AUDIO) {
|
|| (format->u.raw_audio.byte_order
|
||||||
|
!= media_raw_audio_format::wildcard.byte_order
|
||||||
|
&& format->u.raw_audio.byte_order
|
||||||
|
!= fPreferredFormat.u.raw_audio.byte_order)) {
|
||||||
TRACE(" -> B_MEDIA_BAD_FORMAT\n");
|
TRACE(" -> B_MEDIA_BAD_FORMAT\n");
|
||||||
|
*format = fPreferredFormat;
|
||||||
return B_MEDIA_BAD_FORMAT;
|
return B_MEDIA_BAD_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format->type = B_MEDIA_RAW_AUDIO;
|
||||||
|
format->u.raw_audio.format = fPreferredFormat.u.raw_audio.format;
|
||||||
|
format->u.raw_audio.byte_order = fPreferredFormat.u.raw_audio.byte_order;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,13 +243,10 @@ AudioProducer::FormatChangeRequested(const media_source& source,
|
|||||||
return B_MEDIA_BAD_SOURCE;
|
return B_MEDIA_BAD_SOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fOutput.format = *ioFormat;
|
// TODO: Maybe we are supposed to specialize here only and not actually change yet?
|
||||||
|
// status_t ret = _SpecializeFormat(ioFormat);
|
||||||
// notify our audio supplier of the format change
|
|
||||||
if (fSupplier)
|
|
||||||
fSupplier->SetFormat(fOutput.format);
|
|
||||||
|
|
||||||
return _AllocateBuffers(ioFormat);
|
return ChangeFormat(ioFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -333,52 +338,19 @@ AudioProducer::PrepareToConnect(const media_source& what,
|
|||||||
return B_MEDIA_ALREADY_CONNECTED;
|
return B_MEDIA_ALREADY_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the format may not yet be fully specialized (the consumer might have
|
status_t ret = _SpecializeFormat(format);
|
||||||
// passed back some wildcards). Finish specializing it now, and return an
|
if (ret != B_OK) {
|
||||||
// error if we don't support the requested format.
|
TRACE(" -> format error: %s\n", strerror(ret));
|
||||||
if (format->type != B_MEDIA_RAW_AUDIO) {
|
return ret;
|
||||||
TRACE(" -> B_MEDIA_BAD_FORMAT\n");
|
|
||||||
return B_MEDIA_BAD_FORMAT;
|
|
||||||
// TODO: we might want to support different audio formats
|
|
||||||
} else if (format->u.raw_audio.format
|
|
||||||
!= fPreferredFormat.u.raw_audio.format) {
|
|
||||||
TRACE(" -> B_MEDIA_BAD_FORMAT\n");
|
|
||||||
return B_MEDIA_BAD_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format->u.raw_audio.channel_count
|
|
||||||
== media_raw_audio_format::wildcard.channel_count) {
|
|
||||||
format->u.raw_audio.channel_count = 2;
|
|
||||||
TRACE(" -> adjusting channel count, it was wildcard\n");
|
|
||||||
}
|
|
||||||
if (format->u.raw_audio.frame_rate
|
|
||||||
== media_raw_audio_format::wildcard.frame_rate) {
|
|
||||||
format->u.raw_audio.frame_rate = 44100.0;
|
|
||||||
TRACE(" -> adjusting frame rate, it was wildcard\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the buffer size, which may still be wildcarded
|
|
||||||
if (format->u.raw_audio.buffer_size
|
|
||||||
== media_raw_audio_format::wildcard.buffer_size) {
|
|
||||||
// pick something comfortable to suggest
|
|
||||||
TRACE(" -> adjusting buffer size, it was wildcard\n");
|
|
||||||
|
|
||||||
// NOTE: the (buffer_size * 1000000) needs to be dividable by
|
|
||||||
// format->u.raw_audio.frame_rate! (We assume frame rate is a multiple of
|
|
||||||
// 25, which it usually is.)
|
|
||||||
format->u.raw_audio.buffer_size
|
|
||||||
= uint32(format->u.raw_audio.frame_rate / 25.0)
|
|
||||||
* (format->u.raw_audio.format
|
|
||||||
& media_raw_audio_format::B_AUDIO_SIZE_MASK);
|
|
||||||
|
|
||||||
if (!fLowLatency)
|
|
||||||
format->u.raw_audio.buffer_size *= 3;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now reserve the connection, and return information about it
|
// Now reserve the connection, and return information about it
|
||||||
fOutput.destination = where;
|
fOutput.destination = where;
|
||||||
fOutput.format = *format;
|
fOutput.format = *format;
|
||||||
|
|
||||||
|
if (fSupplier != NULL)
|
||||||
|
fSupplier->SetFormat(fOutput.format);
|
||||||
|
|
||||||
*_source = fOutput.source;
|
*_source = fOutput.source;
|
||||||
strncpy(_name, fOutput.name, B_MEDIA_NAME_LENGTH);
|
strncpy(_name, fOutput.name, B_MEDIA_NAME_LENGTH);
|
||||||
TRACE(" -> B_OK\n");
|
TRACE(" -> B_OK\n");
|
||||||
@@ -479,8 +451,8 @@ AudioProducer::Connect(status_t error, const media_source& source,
|
|||||||
// us a buffer group (via SetBufferGroup()) prior to this. That can
|
// us a buffer group (via SetBufferGroup()) prior to this. That can
|
||||||
// happen, for example, if the consumer calls SetOutputBuffersFor() on
|
// happen, for example, if the consumer calls SetOutputBuffersFor() on
|
||||||
// us from within its Connected() method.
|
// us from within its Connected() method.
|
||||||
if (!fBufferGroup)
|
if (fBufferGroup == NULL)
|
||||||
_AllocateBuffers(&fOutput.format);
|
_AllocateBuffers(fOutput.format);
|
||||||
|
|
||||||
TRACE("AudioProducer::Connect() done\n");
|
TRACE("AudioProducer::Connect() done\n");
|
||||||
}
|
}
|
||||||
@@ -615,7 +587,7 @@ void
|
|||||||
AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness,
|
AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness,
|
||||||
bool realTimeEvent)
|
bool realTimeEvent)
|
||||||
{
|
{
|
||||||
TRACE("%p->AudioProducer::HandleEvent()\n", this);
|
TRACE_BUFFER("%p->AudioProducer::HandleEvent()\n", this);
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case BTimedEventQueue::B_START:
|
case BTimedEventQueue::B_START:
|
||||||
@@ -639,7 +611,7 @@ printf("B_START: start time: %lld\n", fStartTime);
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BTimedEventQueue::B_HANDLE_BUFFER: {
|
case BTimedEventQueue::B_HANDLE_BUFFER: {
|
||||||
TRACE("AudioProducer::HandleEvent(B_HANDLE_BUFFER)\n");
|
TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER)\n");
|
||||||
if ((RunState() == BMediaEventLooper::B_STARTED)
|
if ((RunState() == BMediaEventLooper::B_STARTED)
|
||||||
&& (fOutput.destination != media_destination::null)) {
|
&& (fOutput.destination != media_destination::null)) {
|
||||||
BBuffer* buffer = _FillNextBuffer(event->event_time);
|
BBuffer* buffer = _FillNextBuffer(event->event_time);
|
||||||
@@ -665,9 +637,9 @@ printf("B_START: start time: %lld\n", fStartTime);
|
|||||||
BTimedEventQueue::B_HANDLE_BUFFER);
|
BTimedEventQueue::B_HANDLE_BUFFER);
|
||||||
EventQueue()->AddEvent(nextBufferEvent);
|
EventQueue()->AddEvent(nextBufferEvent);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "B_HANDLE_BUFFER, but not started!\n");
|
ERROR("B_HANDLE_BUFFER, but not started!\n");
|
||||||
}
|
}
|
||||||
TRACE("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n");
|
TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -676,15 +648,6 @@ printf("B_START: start time: %lld\n", fStartTime);
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioProducer::SetRunning(bool running)
|
|
||||||
{
|
|
||||||
TRACE("%p->AudioProducer::SetRunning(%d)\n", this, running);
|
|
||||||
|
|
||||||
fRunning = running;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioProducer::SetPeakListener(BHandler* handler)
|
AudioProducer::SetPeakListener(BHandler* handler)
|
||||||
{
|
{
|
||||||
@@ -692,11 +655,104 @@ AudioProducer::SetPeakListener(BHandler* handler)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AudioProducer::ChangeFormat(media_format* format)
|
||||||
|
{
|
||||||
|
TRACE("AudioProducer::ChangeFormat()\n");
|
||||||
|
|
||||||
|
format->u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size;
|
||||||
|
|
||||||
|
status_t ret = _SpecializeFormat(format);
|
||||||
|
if (ret != B_OK) {
|
||||||
|
TRACE(" _SpecializeFormat(): %s\n", strerror(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = BBufferProducer::ProposeFormatChange(format, fOutput.destination);
|
||||||
|
if (ret != B_OK) {
|
||||||
|
TRACE(" ProposeFormatChange(): %s\n", strerror(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = BBufferProducer::ChangeFormat(fOutput.source, fOutput.destination, format);
|
||||||
|
if (ret != B_OK) {
|
||||||
|
TRACE(" ChangeFormat(): %s\n", strerror(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _ChangeFormat(*format);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AudioProducer::_AllocateBuffers(media_format* format)
|
AudioProducer::_SpecializeFormat(media_format* format)
|
||||||
|
{
|
||||||
|
// the format may not yet be fully specialized (the consumer might have
|
||||||
|
// passed back some wildcards). Finish specializing it now, and return an
|
||||||
|
// error if we don't support the requested format.
|
||||||
|
if (format->type != B_MEDIA_RAW_AUDIO) {
|
||||||
|
TRACE(" not raw audio\n");
|
||||||
|
return B_MEDIA_BAD_FORMAT;
|
||||||
|
// TODO: we might want to support different audio formats
|
||||||
|
} else if (format->u.raw_audio.format
|
||||||
|
!= fPreferredFormat.u.raw_audio.format) {
|
||||||
|
TRACE(" format does not match\n");
|
||||||
|
return B_MEDIA_BAD_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format->u.raw_audio.channel_count
|
||||||
|
== media_raw_audio_format::wildcard.channel_count) {
|
||||||
|
format->u.raw_audio.channel_count = 2;
|
||||||
|
TRACE(" -> adjusting channel count, it was wildcard\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format->u.raw_audio.frame_rate
|
||||||
|
== media_raw_audio_format::wildcard.frame_rate) {
|
||||||
|
format->u.raw_audio.frame_rate = 44100.0;
|
||||||
|
TRACE(" -> adjusting frame rate, it was wildcard\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the buffer size, which may still be wildcarded
|
||||||
|
if (format->u.raw_audio.buffer_size
|
||||||
|
== media_raw_audio_format::wildcard.buffer_size) {
|
||||||
|
// pick something comfortable to suggest
|
||||||
|
TRACE(" -> adjusting buffer size, it was wildcard\n");
|
||||||
|
|
||||||
|
// NOTE: the (buffer_size * 1000000) needs to be dividable by
|
||||||
|
// format->u.raw_audio.frame_rate! (We assume frame rate is a multiple of
|
||||||
|
// 25, which it usually is.)
|
||||||
|
format->u.raw_audio.buffer_size
|
||||||
|
= uint32(format->u.raw_audio.frame_rate / 25.0)
|
||||||
|
* (format->u.raw_audio.format
|
||||||
|
& media_raw_audio_format::B_AUDIO_SIZE_MASK);
|
||||||
|
|
||||||
|
if (!fLowLatency)
|
||||||
|
format->u.raw_audio.buffer_size *= 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AudioProducer::_ChangeFormat(const media_format& format)
|
||||||
|
{
|
||||||
|
fOutput.format = format;
|
||||||
|
|
||||||
|
// notify our audio supplier of the format change
|
||||||
|
if (fSupplier)
|
||||||
|
fSupplier->SetFormat(format);
|
||||||
|
|
||||||
|
return _AllocateBuffers(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AudioProducer::_AllocateBuffers(const media_format& format)
|
||||||
{
|
{
|
||||||
TRACE("%p->AudioProducer::_AllocateBuffers()\n", this);
|
TRACE("%p->AudioProducer::_AllocateBuffers()\n", this);
|
||||||
|
|
||||||
@@ -704,7 +760,7 @@ AudioProducer::_AllocateBuffers(media_format* format)
|
|||||||
delete fBufferGroup;
|
delete fBufferGroup;
|
||||||
fBufferGroup = NULL;
|
fBufferGroup = NULL;
|
||||||
}
|
}
|
||||||
size_t size = format->u.raw_audio.buffer_size;
|
size_t size = format.u.raw_audio.buffer_size;
|
||||||
int32 bufferDuration = BufferDuration();
|
int32 bufferDuration = BufferDuration();
|
||||||
int32 count = 0;
|
int32 count = 0;
|
||||||
if (bufferDuration > 0) {
|
if (bufferDuration > 0) {
|
||||||
|
|||||||
@@ -98,13 +98,15 @@ public:
|
|||||||
bigtime_t lateness,
|
bigtime_t lateness,
|
||||||
bool realTimeEvent = false);
|
bool realTimeEvent = false);
|
||||||
|
|
||||||
void SetRunning(bool running);
|
|
||||||
|
|
||||||
// AudioProducer
|
// AudioProducer
|
||||||
void SetPeakListener(BHandler* handler);
|
void SetPeakListener(BHandler* handler);
|
||||||
|
|
||||||
|
status_t ChangeFormat(media_format* format);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _AllocateBuffers(media_format* format);
|
status_t _SpecializeFormat(media_format* format);
|
||||||
|
status_t _ChangeFormat(const media_format& format);
|
||||||
|
status_t _AllocateBuffers(const media_format& format);
|
||||||
BBuffer* _FillNextBuffer(bigtime_t eventTime);
|
BBuffer* _FillNextBuffer(bigtime_t eventTime);
|
||||||
|
|
||||||
void _FillSampleBuffer(float* data,
|
void _FillSampleBuffer(float* data,
|
||||||
@@ -123,7 +125,6 @@ private:
|
|||||||
bigtime_t fStartTime;
|
bigtime_t fStartTime;
|
||||||
|
|
||||||
AudioSupplier* fSupplier;
|
AudioSupplier* fSupplier;
|
||||||
volatile bool fRunning;
|
|
||||||
|
|
||||||
BHandler* fPeakListener;
|
BHandler* fPeakListener;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user