Fix and force USB audio driver to work with new OHCI module
* some functionality like recording temporarily disabled; * set the endpoint speed call added; * packet size hard-coded for 48kHz case; * draft support for formats and sampling rate handling; * implement sampling rate change on the fly; * optimized using of starting frame; * fix user_memory in buffer exchaqnge call; * fix exchanged buffer recoriding processing; * debug tweaks, fix current buffer switching; * cleanup, cleanup, cleanup...
This commit is contained in:
@@ -11,6 +11,29 @@
|
||||
#include "audio.h"
|
||||
|
||||
|
||||
static struct RatePair {
|
||||
uint32 rate;
|
||||
uint32 rateId;
|
||||
} ratesMap[] = {
|
||||
{ 8000, B_SR_8000 },
|
||||
{ 11025, B_SR_11025 },
|
||||
{ 12000, B_SR_12000 },
|
||||
{ 16000, B_SR_16000 },
|
||||
{ 22050, B_SR_22050 },
|
||||
{ 24000, B_SR_24000 },
|
||||
{ 32000, B_SR_32000 },
|
||||
{ 44100, B_SR_44100 },
|
||||
{ 48000, B_SR_48000 },
|
||||
{ 64000, B_SR_64000 },
|
||||
{ 88200, B_SR_88200 },
|
||||
{ 96000, B_SR_96000 },
|
||||
{ 176400, B_SR_176400 },
|
||||
{ 192000, B_SR_192000 },
|
||||
{ 384000, B_SR_384000 },
|
||||
{ 1536000, B_SR_1536000 }
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Audio Stream information entities
|
||||
//
|
||||
@@ -44,28 +67,31 @@ ASInterfaceDescriptor::~ASInterfaceDescriptor()
|
||||
ASEndpointDescriptor::ASEndpointDescriptor(usb_endpoint_descriptor* Endpoint,
|
||||
usb_as_cs_endpoint_descriptor* Descriptor)
|
||||
:
|
||||
fAttributes(0),
|
||||
fCSAttributes(0),
|
||||
fLockDelayUnits(0),
|
||||
fLockDelay(0),
|
||||
fMaxPacketSize(0),
|
||||
fEndpointAddress(0)
|
||||
fEndpointAddress(0),
|
||||
fEndpointAttributes(0)
|
||||
{
|
||||
// usb_audiocontrol_header_descriptor *Header
|
||||
// = (usb_audiocontrol_header_descriptor *)Interface->generic[i];
|
||||
|
||||
fAttributes = Descriptor->attributes;
|
||||
fCSAttributes = Descriptor->attributes;
|
||||
fLockDelayUnits = Descriptor->lock_delay_units;
|
||||
fLockDelay = Descriptor->lock_delay;
|
||||
|
||||
// usb_endpoint_descriptor* endpoint = Interface->endpoint[0]->descr;
|
||||
fEndpointAttributes = Endpoint->attributes;
|
||||
fEndpointAddress = Endpoint->endpoint_address;
|
||||
fMaxPacketSize = Endpoint->max_packet_size;
|
||||
|
||||
TRACE("fAttributes:%d\n", fAttributes);
|
||||
TRACE("fCSAttributes:%d\n", fCSAttributes);
|
||||
TRACE("fLockDelayUnits:%d\n", fLockDelayUnits);
|
||||
TRACE("fLockDelay:%d\n", fLockDelay);
|
||||
TRACE("fMaxPacketSize:%d\n", fMaxPacketSize);
|
||||
TRACE("fEndpointAddress:%#02x\n", fEndpointAddress);
|
||||
TRACE("fEndpointAttributes:%d\n", fEndpointAttributes);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,8 +212,10 @@ AudioStreamAlternate::AudioStreamAlternate(size_t alternate,
|
||||
fAlternate(alternate),
|
||||
fInterface(interface),
|
||||
fEndpoint(endpoint),
|
||||
fFormat(format)
|
||||
fFormat(format),
|
||||
fSamplingRate(0)
|
||||
{
|
||||
// SetSamplingRate(0); // init to default (max) sampling rate
|
||||
}
|
||||
|
||||
|
||||
@@ -199,6 +227,166 @@ AudioStreamAlternate::~AudioStreamAlternate()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AudioStreamAlternate::SetSamplingRate(uint32 newRate)
|
||||
{
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(Format());
|
||||
|
||||
if (format == NULL) {
|
||||
TRACE_ALWAYS("Format not set for active alternate\n");
|
||||
return B_NO_INIT;
|
||||
}
|
||||
|
||||
Vector<uint32>& frequencies = format->fSampleFrequencies;
|
||||
bool continuous = format->fSampleFrequencyType == 0;
|
||||
|
||||
if (newRate == 0) { // by default select max available
|
||||
fSamplingRate = 0;
|
||||
if (continuous)
|
||||
fSamplingRate = max_c(frequencies[0], frequencies[1]);
|
||||
else
|
||||
for (int i = 0; i < frequencies.Count(); i++)
|
||||
fSamplingRate = max_c(fSamplingRate, frequencies[i]);
|
||||
} else {
|
||||
if (continuous) {
|
||||
uint32 min = min_c(frequencies[0], frequencies[1]);
|
||||
uint32 max = max_c(frequencies[0], frequencies[1]);
|
||||
if (newRate < min || newRate > max) {
|
||||
TRACE_ALWAYS("Rate %d outside of %d - %d ignored.\n",
|
||||
newRate, min, max);
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
fSamplingRate = newRate;
|
||||
} else {
|
||||
for (int i = 0; i < frequencies.Count(); i++)
|
||||
if (newRate == frequencies[i]) {
|
||||
fSamplingRate = newRate;
|
||||
return B_OK;
|
||||
}
|
||||
TRACE_ALWAYS("Rate %d not found - ignore it.\n", newRate);
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
// newRate = fSamplingRate;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AudioStreamAlternate::GetSamplingRateId(uint32 rate)
|
||||
{
|
||||
if (rate == 0)
|
||||
rate = fSamplingRate;
|
||||
|
||||
for (size_t i = 0; i < _countof(ratesMap); i++)
|
||||
if (ratesMap[i].rate == rate)
|
||||
return ratesMap[i].rateId;
|
||||
|
||||
TRACE_ALWAYS("Ignore unsupported sample rate %d.\n", rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AudioStreamAlternate::GetSamplingRateIds()
|
||||
{
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(Format());
|
||||
|
||||
if (format == NULL) {
|
||||
TRACE_ALWAYS("Format not set for active alternate\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 rates = 0;
|
||||
Vector<uint32>& frequencies = format->fSampleFrequencies;
|
||||
if (format->fSampleFrequencyType == 0) { // continuous frequencies
|
||||
uint32 min = min_c(frequencies[0], frequencies[1]);
|
||||
uint32 max = max_c(frequencies[0], frequencies[1]);
|
||||
|
||||
for (int i = 0; i < frequencies.Count(); i++) {
|
||||
if (frequencies[i] < min || frequencies[i] > max)
|
||||
continue;
|
||||
rates |= GetSamplingRateId(frequencies[i]);
|
||||
}
|
||||
} else
|
||||
for (int i = 0; i < frequencies.Count(); i++)
|
||||
rates |= GetSamplingRateId(frequencies[i]);
|
||||
|
||||
return rates;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AudioStreamAlternate::GetFormatId()
|
||||
{
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(Format());
|
||||
|
||||
if (format == NULL || Interface() == NULL) {
|
||||
TRACE_ALWAYS("Ignore alternate due format "
|
||||
"%#08x or interface %#08x null.\n", format, Interface());
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 formats = 0;
|
||||
switch (Interface()->fFormatTag) {
|
||||
case UAF_PCM8: formats = B_FMT_8BIT_U; break;
|
||||
case UAF_IEEE_FLOAT: formats = B_FMT_FLOAT; break;
|
||||
case UAF_PCM:
|
||||
switch(format->fBitResolution) {
|
||||
case 8: formats = B_FMT_8BIT_S; break;
|
||||
case 16: formats = B_FMT_16BIT; break;
|
||||
case 18: formats = B_FMT_18BIT; break;
|
||||
case 20: formats = B_FMT_20BIT; break;
|
||||
case 24: formats = B_FMT_24BIT; break;
|
||||
case 32: formats = B_FMT_32BIT; break;
|
||||
default:
|
||||
TRACE_ALWAYS("Ignore unsupported "
|
||||
"bit resolution %d for alternate.\n",
|
||||
format->fBitResolution);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TRACE_ALWAYS("Ignore unsupported "
|
||||
"format bit resolution %d for alternate.\n",
|
||||
Interface()->fFormatTag);
|
||||
break;
|
||||
}
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AudioStreamAlternate::SamplingRateFromId(uint32 id)
|
||||
{
|
||||
for (size_t i = 0; i < _countof(ratesMap); i++)
|
||||
if (ratesMap[i].rateId == id)
|
||||
return ratesMap[i].rate;
|
||||
|
||||
TRACE_ALWAYS("Unknown sample rate id: %d.\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AudioStreamAlternate::SetSamplingRateById(uint32 newId)
|
||||
{
|
||||
return SetSamplingRate(SamplingRateFromId(newId));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AudioStreamAlternate::SetFormatId(uint32 /*newFormatId*/)
|
||||
{
|
||||
return B_OK; // TODO
|
||||
}
|
||||
|
||||
|
||||
AudioStreamingInterface::AudioStreamingInterface(
|
||||
AudioControlInterface* controlInterface,
|
||||
size_t interface, usb_interface_list *List)
|
||||
@@ -329,9 +517,8 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description)
|
||||
Description->interface_flags
|
||||
|= fIsInput ? B_MULTI_INTERFACE_RECORD : B_MULTI_INTERFACE_PLAYBACK;
|
||||
|
||||
uint32 rates = 0;
|
||||
uint32 formats = 0;
|
||||
|
||||
// uint32 rates = 0;
|
||||
/*
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(
|
||||
fAlternates[fActiveAlternate]->Format());
|
||||
@@ -373,27 +560,9 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (fAlternates[fActiveAlternate]->Interface()->fFormatTag) {
|
||||
case UAF_PCM8: formats = B_FMT_8BIT_U; break;
|
||||
case UAF_IEEE_FLOAT: formats = B_FMT_FLOAT; break;
|
||||
case UAF_PCM:
|
||||
switch(format->fBitResolution) {
|
||||
case 8: formats = B_FMT_8BIT_S; break;
|
||||
case 16: formats = B_FMT_16BIT; break;
|
||||
case 18: formats = B_FMT_18BIT; break;
|
||||
case 20: formats = B_FMT_20BIT; break;
|
||||
case 24: formats = B_FMT_24BIT; break;
|
||||
case 32: formats = B_FMT_32BIT; break;
|
||||
break;
|
||||
default:
|
||||
TRACE_ALWAYS("Ignore unsupported "
|
||||
"bit resolution %d for alternate %d.\n",
|
||||
format->fBitResolution, fActiveAlternate);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
uint32 rates = fAlternates[fActiveAlternate]->GetSamplingRateIds();
|
||||
uint32 formats = fAlternates[fActiveAlternate]->GetFormatId();
|
||||
|
||||
if (fIsInput) {
|
||||
Description->input_rates = rates;
|
||||
|
||||
@@ -40,11 +40,12 @@ public:
|
||||
~ASEndpointDescriptor();
|
||||
|
||||
// protected:
|
||||
uint8 fAttributes;
|
||||
uint8 fCSAttributes;
|
||||
uint8 fLockDelayUnits;
|
||||
uint16 fLockDelay;
|
||||
uint16 fMaxPacketSize;
|
||||
uint8 fEndpointAddress;
|
||||
uint8 fEndpointAttributes;
|
||||
};
|
||||
|
||||
|
||||
@@ -113,11 +114,22 @@ public:
|
||||
ASEndpointDescriptor* Endpoint() { return fEndpoint; }
|
||||
_ASFormatDescriptor* Format() { return fFormat; }
|
||||
|
||||
status_t SetSamplingRate(uint32 newRate);
|
||||
status_t SetSamplingRateById(uint32 newId);
|
||||
uint32 GetSamplingRate() { return fSamplingRate; }
|
||||
uint32 GetSamplingRateId(uint32 rate);
|
||||
uint32 GetSamplingRateIds();
|
||||
uint32 GetFormatId();
|
||||
status_t SetFormatId(uint32 newFormatId);
|
||||
uint32 SamplingRateFromId(uint32 id);
|
||||
|
||||
protected:
|
||||
|
||||
size_t fAlternate;
|
||||
ASInterfaceDescriptor* fInterface;
|
||||
ASEndpointDescriptor* fEndpoint;
|
||||
_ASFormatDescriptor* fFormat;
|
||||
uint32 fSamplingRate;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ Device::Device(usb_device device)
|
||||
fDevice(device),
|
||||
fNonBlocking(false),
|
||||
fAudioControl(this),
|
||||
fControlEndpoint(0),
|
||||
fInStreamEndpoint(0),
|
||||
fOutStreamEndpoint(0),
|
||||
// fControlEndpoint(0),
|
||||
// fInStreamEndpoint(0),
|
||||
// fOutStreamEndpoint(0),
|
||||
fNotifyReadSem(-1),
|
||||
fNotifyWriteSem(-1),
|
||||
fNotifyBuffer(NULL),
|
||||
@@ -42,6 +42,7 @@ Device::Device(usb_device device)
|
||||
|
||||
fVendorID = deviceDescriptor->vendor_id;
|
||||
fProductID = deviceDescriptor->product_id;
|
||||
fUSBVersion = deviceDescriptor->usb_version;
|
||||
|
||||
fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read");
|
||||
if (fNotifyReadSem < B_OK) {
|
||||
@@ -155,9 +156,9 @@ Device::Close()
|
||||
// wait until possible notification handling finished...
|
||||
while (atomic_add(&fInsideNotify, 0) != 0)
|
||||
snooze(100);
|
||||
gUSBModule->cancel_queued_transfers(fControlEndpoint);
|
||||
gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
|
||||
gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
|
||||
// gUSBModule->cancel_queued_transfers(fControlEndpoint);
|
||||
// gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
|
||||
// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
|
||||
|
||||
fOpen = false;
|
||||
|
||||
@@ -289,9 +290,9 @@ Device::Removed()
|
||||
while (atomic_add(&fInsideNotify, 0) != 0)
|
||||
snooze(100);
|
||||
|
||||
gUSBModule->cancel_queued_transfers(fControlEndpoint);
|
||||
gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
|
||||
gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
|
||||
// gUSBModule->cancel_queued_transfers(fControlEndpoint);
|
||||
// gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
|
||||
// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
|
||||
/*
|
||||
if (fLinkStateChangeSem >= B_OK)
|
||||
release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
|
||||
@@ -415,7 +416,7 @@ Device::_MultiGetDescription(multi_description *multiDescription)
|
||||
TraceMultiDescription(&Description, Channels);
|
||||
|
||||
if (user_memcpy(multiDescription, &Description,
|
||||
sizeof(multi_description)) != B_OK) {
|
||||
sizeof(multi_description)) != B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -555,6 +556,10 @@ Device::_MultiGetBuffers(multi_buffer_list* List)
|
||||
List->request_record_channels,
|
||||
List->request_record_buffer_size);
|
||||
|
||||
List->flags = 0;
|
||||
List->return_playback_channels = 0;
|
||||
List->return_record_channels = 0;
|
||||
|
||||
for (int i = 0; i < fStreams.Count() && status == B_OK; i++) {
|
||||
status = fStreams[i]->GetBuffers(List);
|
||||
}
|
||||
@@ -564,18 +569,23 @@ Device::_MultiGetBuffers(multi_buffer_list* List)
|
||||
|
||||
|
||||
status_t
|
||||
Device::_MultiBufferExchange(multi_buffer_info* Info)
|
||||
Device::_MultiBufferExchange(multi_buffer_info* multiInfo)
|
||||
{
|
||||
multi_buffer_info Info;
|
||||
if (user_memcpy(&Info, multiInfo, sizeof(multi_buffer_info)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
for (int i = 0; i < fStreams.Count(); i++) {
|
||||
if (!fStreams[i]->IsRunning()) {
|
||||
fStreams[i]->Start();
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_ALWAYS("Exchange!\n");
|
||||
// TRACE_ALWAYS("Exchange!\n");
|
||||
/*
|
||||
snooze(1000000);
|
||||
return B_OK;
|
||||
|
||||
*/
|
||||
status_t status = B_ERROR;
|
||||
bool anyBufferProcessed = false;
|
||||
for (int i = 0; i < fStreams.Count() && !anyBufferProcessed; i++) {
|
||||
@@ -586,10 +596,13 @@ Device::_MultiBufferExchange(multi_buffer_info* Info)
|
||||
break;
|
||||
}
|
||||
|
||||
anyBufferProcessed = fStreams[i]->ExchangeBuffer(Info);
|
||||
anyBufferProcessed = fStreams[i]->ExchangeBuffer(&Info);
|
||||
status = anyBufferProcessed ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
if (user_memcpy(multiInfo, &Info, sizeof(multi_buffer_info)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -713,7 +726,7 @@ Device::_SetupEndpoints()
|
||||
status_t
|
||||
Device::StopDevice()
|
||||
{
|
||||
status_t result = B_OK; // WriteRXControlRegister(0);
|
||||
status_t result = B_OK;
|
||||
|
||||
if (result != B_OK) {
|
||||
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
|
||||
|
||||
@@ -81,6 +81,7 @@ virtual status_t StopDevice();
|
||||
bool fRemoved;
|
||||
vint32 fInsideNotify;
|
||||
usb_device fDevice;
|
||||
uint16 fUSBVersion;
|
||||
uint16 fVendorID;
|
||||
uint16 fProductID;
|
||||
const char * fDescription;
|
||||
@@ -116,9 +117,9 @@ protected:
|
||||
// uint16 fFrameSize;
|
||||
|
||||
// pipes for notifications and data io
|
||||
usb_pipe fControlEndpoint;
|
||||
usb_pipe fInStreamEndpoint;
|
||||
usb_pipe fOutStreamEndpoint;
|
||||
// usb_pipe fControlEndpoint;
|
||||
// usb_pipe fInStreamEndpoint;
|
||||
// usb_pipe fOutStreamEndpoint;
|
||||
|
||||
// data stores for async usb transfers
|
||||
uint32 fActualLengthRead;
|
||||
|
||||
@@ -21,18 +21,16 @@ Stream::Stream(Device *device, size_t interface, usb_interface_list *List
|
||||
fStreamEndpoint(0),
|
||||
fIsRunning(false),
|
||||
fArea(-1),
|
||||
fDescriptors(0),
|
||||
fAreaSize(0),
|
||||
fDescriptors(NULL),
|
||||
fDescriptorsCount(0),
|
||||
fCurrentBuffer(0),
|
||||
fStartingFrame(0),
|
||||
fSamplesCount(0),
|
||||
fProcessedBuffers(0)/*,
|
||||
fBuffersPhysAddress(0)/ *,
|
||||
fRealTime(0),
|
||||
fFramesCount(0),
|
||||
fBufferCycle(0)*/
|
||||
fPacketSize(0),
|
||||
fProcessedBuffers(0)
|
||||
{
|
||||
|
||||
memset(&fFormat, 0, sizeof(_multi_format));
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +41,7 @@ Stream::~Stream()
|
||||
|
||||
|
||||
status_t
|
||||
Stream::Init()
|
||||
Stream::_ChooseAlternate()
|
||||
{
|
||||
// lookup alternate with maximal (ch * 100 + resolution)
|
||||
uint16 maxChxRes = 0;
|
||||
@@ -80,6 +78,12 @@ Stream::Init()
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(fAlternates[i]->Format());
|
||||
|
||||
if (format->fNumChannels > 2) {
|
||||
TRACE("Ignore alternate %d - channel count %d "
|
||||
"is not supported.\n", i, format->fNumChannels);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fAlternates[i]->Interface()->fFormatTag == UAF_PCM) {
|
||||
switch(format->fBitResolution) {
|
||||
default:
|
||||
@@ -100,80 +104,94 @@ Stream::Init()
|
||||
|
||||
if (maxChxRes <= 0) {
|
||||
TRACE("No compatible alternate found. Stream initialization failed.\n");
|
||||
return fStatus;
|
||||
return B_NO_INIT;
|
||||
}
|
||||
|
||||
const ASEndpointDescriptor* endpoint = fAlternates[
|
||||
fActiveAlternate]->Endpoint();
|
||||
fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN)
|
||||
== USB_ENDPOINT_ADDR_DIR_IN;
|
||||
TRACE("Alternate %d selected!\n", fActiveAlternate);
|
||||
TRACE("Alternate %d EP:%x selected for %s!\n",
|
||||
fActiveAlternate, endpoint->fEndpointAddress,
|
||||
fIsInput ? "recording" : "playback");
|
||||
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(fAlternates[
|
||||
fActiveAlternate]->Format());
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
size_t bufferSize = format->fNumChannels * format->fSubframeSize;
|
||||
TRACE("bufferSize:%d\n", bufferSize);
|
||||
|
||||
bufferSize *= kSamplesBufferSize;
|
||||
TRACE("bufferSize:%d\n", bufferSize);
|
||||
status_t
|
||||
Stream::Init()
|
||||
{
|
||||
fStatus = _ChooseAlternate();
|
||||
//if (fStatus != B_OK)
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
bufferSize *= (sizeof(usb_iso_packet_descriptor) + endpoint->fMaxPacketSize);
|
||||
TRACE("bufferSize:%d\n", bufferSize);
|
||||
|
||||
bufferSize /= endpoint->fMaxPacketSize;
|
||||
TRACE("bufferSize:%d\n", bufferSize);
|
||||
status_t
|
||||
Stream::_SetupBuffers()
|
||||
{
|
||||
// allocate buffer for worst (maximal size) case
|
||||
TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
|
||||
fAlternates[fActiveAlternate]->Format());
|
||||
|
||||
uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
|
||||
uint32 sampleSize = format->fNumChannels * format->fSubframeSize;
|
||||
|
||||
// data size pro 1 ms USB 1 frame or 1/8 ms USB 2 microframe
|
||||
fPacketSize = samplingRate * sampleSize
|
||||
/ (fDevice->fUSBVersion < 0x0200 ? 1000 : 8000);
|
||||
TRACE("packetSize:%ld\n", fPacketSize);
|
||||
|
||||
bufferSize = (bufferSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
|
||||
TRACE("bufferSize:%d\n", bufferSize);
|
||||
if (fArea == -1) {
|
||||
fAreaSize = (sizeof(usb_iso_packet_descriptor) + fPacketSize)
|
||||
* sampleSize * 1024 / fPacketSize;
|
||||
TRACE("estimate fAreaSize:%d\n", fAreaSize);
|
||||
|
||||
fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area" :
|
||||
DRIVER_NAME "_playback_area",
|
||||
(void**)&fDescriptors, B_ANY_KERNEL_ADDRESS,
|
||||
bufferSize, B_CONTIGUOUS,
|
||||
B_READ_AREA | B_WRITE_AREA);
|
||||
if (fArea < 0) {
|
||||
TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n",
|
||||
bufferSize, fArea);
|
||||
fStatus = fArea;
|
||||
return fStatus;
|
||||
// round up to B_PAGE_SIZE and create area
|
||||
fAreaSize = (fAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
|
||||
TRACE("rounded up fAreaSize:%d\n", fAreaSize);
|
||||
|
||||
fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area"
|
||||
: DRIVER_NAME "_playback_area", (void**)&fDescriptors,
|
||||
B_ANY_KERNEL_ADDRESS, fAreaSize, B_CONTIGUOUS,
|
||||
B_READ_AREA | B_WRITE_AREA);
|
||||
|
||||
if (fArea < 0) {
|
||||
TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n",
|
||||
fAreaSize, fArea);
|
||||
fStatus = fArea;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
// physical_entry PhysEntry;
|
||||
// get_memory_map(fDescriptors, fAreaSize, &PhysEntry, 1);
|
||||
|
||||
TRACE_ALWAYS("Created area id:%d at addr:%#010x size:%#010lx\n",
|
||||
fArea, fDescriptors, fAreaSize);
|
||||
}
|
||||
|
||||
physical_entry PhysEntry;
|
||||
get_memory_map(fDescriptors, bufferSize, &PhysEntry, 1);
|
||||
|
||||
TRACE_ALWAYS("Created area id: "
|
||||
"%d\naddress:%#010x[phys:%#010x]\nsize:%#010x\n",
|
||||
fArea, fDescriptors, PhysEntry.address, bufferSize);
|
||||
|
||||
fDescriptorsCount = bufferSize;
|
||||
fDescriptorsCount /= (sizeof(usb_iso_packet_descriptor)
|
||||
+ endpoint->fMaxPacketSize);
|
||||
// descriptors count
|
||||
fDescriptorsCount = fAreaSize
|
||||
/ (sizeof(usb_iso_packet_descriptor) + fPacketSize);
|
||||
|
||||
// we need same size sub-buffers. round it
|
||||
fDescriptorsCount /= kSamplesBufferCount;
|
||||
// we need same size buffers. round it!
|
||||
fDescriptorsCount *= kSamplesBufferCount;
|
||||
TRACE("descriptorsCount:%d\n", fDescriptorsCount);
|
||||
|
||||
fSamplesCount = fDescriptorsCount * endpoint->fMaxPacketSize;
|
||||
TRACE("samplesCount:%d\n", fSamplesCount);
|
||||
|
||||
fSamplesCount /= format->fNumChannels * format->fSubframeSize;
|
||||
// samples count
|
||||
fSamplesCount = fDescriptorsCount * fPacketSize / sampleSize;
|
||||
TRACE("samplesCount:%d\n", fSamplesCount);
|
||||
|
||||
// initialize descriptors array
|
||||
for (size_t i = 0; i < fDescriptorsCount; i++) {
|
||||
fDescriptors[i].request_length = endpoint->fMaxPacketSize;
|
||||
fDescriptors[i].request_length = fPacketSize;
|
||||
fDescriptors[i].actual_length = 0;
|
||||
fDescriptors[i].status = B_OK;
|
||||
}
|
||||
|
||||
/* uint32* b = (uint32*)(fDescriptors + fDescriptorsCount);
|
||||
for (size_t i = 0; i < fSamplesCount; i++) {
|
||||
b[i] = i * 10;
|
||||
}*/
|
||||
|
||||
TRACE_ALWAYS("Descriptors count:%d\nsample size:%d\nchannels:%d:%d\n",
|
||||
fDescriptorsCount, format->fSubframeSize, format->fNumChannels,
|
||||
sizeof(usb_iso_packet_descriptor));
|
||||
return fStatus = B_OK;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,14 +211,32 @@ Stream::OnSetConfiguration(usb_device device,
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/*status_t status =*/ gUSBModule->set_alt_interface(device, interface);
|
||||
status_t status = gUSBModule->set_alt_interface(device, interface);
|
||||
uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
|
||||
|
||||
TRACE_ALWAYS("set_alt_interface %x\n", status);
|
||||
|
||||
for (size_t i = 0; i < interface->endpoint_count; i++) {
|
||||
if (address == interface->endpoint[i].descr->endpoint_address) {
|
||||
fStreamEndpoint = interface->endpoint[i].handle;
|
||||
TRACE("%s Stream Endpoint [address %#04x] handle is: %#010x.\n",
|
||||
fIsInput ? "Input" : "Output", address, fStreamEndpoint);
|
||||
/*
|
||||
size_t actualLength = 0;
|
||||
uint32 speed = 48000;
|
||||
uint8 data[3];
|
||||
data[0] = 0xFF & speed;
|
||||
data[1] = (uint8) 0xFF & speed >> 8;
|
||||
data[2] = (uint8) 0xFF & speed >> 16;
|
||||
|
||||
status_t status = gUSBModule->send_request(device,
|
||||
USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT,
|
||||
UAS_SET_CUR, UAS_SAMPLING_FREQ_CONTROL << 8,
|
||||
address, 3, data, &actualLength);
|
||||
|
||||
TRACE_ALWAYS("set_speed for ep %#x %d: %x\n",
|
||||
address, actualLength, status);
|
||||
*/
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
@@ -216,12 +252,9 @@ Stream::Start()
|
||||
{
|
||||
status_t result = B_BUSY;
|
||||
if (!fIsRunning) {
|
||||
if (!fIsInput) {
|
||||
// for (size_t i = 0; i < kSamplesBufferCount; i++)
|
||||
// result = _QueueNextTransfer(i);
|
||||
// TODO
|
||||
// result = _QueueNextTransfer(0);
|
||||
result = B_OK;
|
||||
if (!fIsInput) { // TODO: recording
|
||||
for (size_t i = 0; i < kSamplesBufferCount; i++)
|
||||
result = _QueueNextTransfer(i, true);
|
||||
} else
|
||||
result = B_OK;
|
||||
fIsRunning = result == B_OK;
|
||||
@@ -243,7 +276,7 @@ Stream::Stop()
|
||||
|
||||
|
||||
status_t
|
||||
Stream::_QueueNextTransfer(size_t queuedBuffer)
|
||||
Stream::_QueueNextTransfer(size_t queuedBuffer, bool start)
|
||||
{
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(fAlternates[
|
||||
@@ -259,14 +292,35 @@ Stream::_QueueNextTransfer(size_t queuedBuffer)
|
||||
TRACE("buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n",
|
||||
buffers + bufferSize * queuedBuffer, bufferSize,
|
||||
fDescriptors + queuedBuffer * packetsCount, packetsCount);
|
||||
#if 0
|
||||
{
|
||||
static int16 sin[24] = { 0, 4277, 8481, 12540, 16384, 19948, 23170, 25996,
|
||||
28378, 30273, 31651, 32487, 32767, 32487, 31651, 30273, 28378, 25996,
|
||||
23170, 19948, 16384, 12540, 8481, 4277 };
|
||||
static uint16 sample = 0;
|
||||
static bool sign = true;
|
||||
|
||||
uint16* b = (uint16*)(buffers + bufferSize * queuedBuffer);
|
||||
size_t length = bufferSize;
|
||||
for (size_t u = 0; u < length / 2; u += 2) {
|
||||
b[u] = b[u + 1] = sign ? sin[sample] : -sin[sample];
|
||||
sample ++;
|
||||
if (sample == 24) {
|
||||
sample = 0;
|
||||
sign = !sign;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return gUSBModule->queue_isochronous(fStreamEndpoint,
|
||||
status_t status = gUSBModule->queue_isochronous(fStreamEndpoint,
|
||||
buffers + bufferSize * queuedBuffer, bufferSize,
|
||||
fDescriptors + queuedBuffer * packetsCount, packetsCount,
|
||||
NULL/*&fStartingFrame*/, USB_ISO_ASAP,
|
||||
&fStartingFrame, start ? USB_ISO_ASAP : 0,
|
||||
Stream::_TransferCallback, this);
|
||||
|
||||
return B_OK;
|
||||
TRACE("frame:%#010x\n", fStartingFrame);
|
||||
return status; // B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,48 +328,39 @@ void
|
||||
Stream::_TransferCallback(void *cookie, int32 status, void *data,
|
||||
uint32 actualLength)
|
||||
{
|
||||
Stream *stream = (Stream *)cookie;
|
||||
|
||||
stream->fCurrentBuffer++;
|
||||
if (stream->fCurrentBuffer >= kSamplesBufferCount) {
|
||||
stream->fCurrentBuffer = 0;
|
||||
if (status == B_CANCELED) {
|
||||
TRACE_ALWAYS("Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n",
|
||||
cookie, status, data, actualLength);
|
||||
return;
|
||||
}
|
||||
|
||||
stream->_DumpDescriptors();
|
||||
Stream *stream = (Stream *)cookie;
|
||||
|
||||
stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount;
|
||||
|
||||
stream->_DumpDescriptors();
|
||||
|
||||
/*
|
||||
status_t result = stream->_QueueNextTransfer(stream->fCurrentBuffer);
|
||||
/*status_t result =*/ stream->_QueueNextTransfer(stream->fCurrentBuffer, false);
|
||||
|
||||
if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount) {
|
||||
TRACE_ALWAYS("Processed buffers overflow:%d\n", stream->fProcessedBuffers);
|
||||
}
|
||||
*/
|
||||
|
||||
release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
|
||||
|
||||
// TRACE_ALWAYS("st:%#010x, len:%d -> %#010x\n", status, actualLength, result);
|
||||
TRACE_ALWAYS("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
|
||||
|
||||
/* if (status != B_OK) {
|
||||
TRACE_ALWAYS("Device status error:%#010x\n", status);
|
||||
status_t result = gUSBModule->clear_feature(device->fControLeNDPOint,
|
||||
USB_FEATURE_ENDPOINT_HALT);
|
||||
if (result != B_OK)
|
||||
TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result);
|
||||
}
|
||||
*/
|
||||
TRACE("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Stream::_DumpDescriptors()
|
||||
{
|
||||
size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
|
||||
//size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
|
||||
size_t from = /*fCurrentBuffer > 0 ? packetsCount :*/ 0 ;
|
||||
size_t to = /*fCurrentBuffer > 0 ?*/ fDescriptorsCount /*: packetsCount*/ ;
|
||||
for (size_t i = from; i < to; i++) {
|
||||
TRACE_ALWAYS("%d:req_len:%d; act_len:%d; stat:%#010x\n", i,
|
||||
TRACE("%d:req_len:%d; act_len:%d; stat:%#010x\n", i,
|
||||
fDescriptors[i].request_length, fDescriptors[i].actual_length,
|
||||
fDescriptors[i].status);
|
||||
}
|
||||
@@ -359,18 +404,13 @@ Stream::SetEnabledChannels(uint32& offset, multi_channel_enable *Enable)
|
||||
status_t
|
||||
Stream::GetGlobalFormat(multi_format_info *Format)
|
||||
{
|
||||
if (IsInput()) {
|
||||
// TODO
|
||||
Format->input.rate = B_SR_48000;
|
||||
Format->input.cvsr = 48000;
|
||||
Format->input.format = B_FMT_16BIT;
|
||||
} else {
|
||||
// TODO
|
||||
Format->output.rate = B_SR_48000;
|
||||
Format->output.cvsr = 48000;
|
||||
Format->output.format = B_FMT_16BIT;
|
||||
}
|
||||
|
||||
_multi_format* format = fIsInput ? &Format->input : &Format->output;
|
||||
format->cvsr = fAlternates[fActiveAlternate]->GetSamplingRate();
|
||||
format->rate = fAlternates[fActiveAlternate]->GetSamplingRateId(0);
|
||||
format->format = fAlternates[fActiveAlternate]->GetFormatId();
|
||||
TRACE("%s.rate:%d cvsr:%f format:%#08x\n",
|
||||
fIsInput ? "input" : "ouput",
|
||||
format->rate, format->cvsr, format->format);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -378,19 +418,49 @@ Stream::GetGlobalFormat(multi_format_info *Format)
|
||||
status_t
|
||||
Stream::SetGlobalFormat(multi_format_info *Format)
|
||||
{
|
||||
if (IsInput()) {
|
||||
// TODO
|
||||
TRACE("input.rate:%d\n", Format->input.rate);
|
||||
TRACE("input.cvsr:%f\n", Format->input.cvsr);
|
||||
TRACE("input.format:%#08x\n", Format->input.format);
|
||||
} else {
|
||||
// TODO
|
||||
TRACE("output.rate:%d\n", Format->output.rate);
|
||||
TRACE("output.cvsr:%f\n", Format->output.cvsr);
|
||||
TRACE("output.format:%#08x\n", Format->output.format);
|
||||
_multi_format* format = fIsInput ? &Format->input : &Format->output;
|
||||
AudioStreamAlternate* alternate = fAlternates[fActiveAlternate];
|
||||
if (format->rate == alternate->GetSamplingRateId(0)
|
||||
&& format->format == alternate->GetFormatId()) {
|
||||
TRACE("No changes required\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
alternate->SetSamplingRateById(format->rate);
|
||||
alternate->SetFormatId(format->format);
|
||||
TRACE("%s.rate:%d cvsr:%f format:%#08x\n",
|
||||
fIsInput ? "input" : "ouput",
|
||||
format->rate, format->cvsr, format->format);
|
||||
|
||||
// cancel data flow - it will be rewaked at next buffer exchange call
|
||||
Stop();
|
||||
|
||||
// TODO: wait for cancelling?
|
||||
|
||||
// layout of buffers should be adjusted after changing sampling rate/format
|
||||
status_t status = _SetupBuffers();
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// set endpoint speed
|
||||
uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
|
||||
size_t actualLength = 0;
|
||||
uint8 data[3];
|
||||
data[0] = 0xFF & samplingRate;
|
||||
data[1] = 0xFF & samplingRate >> 8;
|
||||
data[2] = 0xFF & samplingRate >> 16;
|
||||
uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
|
||||
|
||||
status = gUSBModule->send_request(fDevice->fDevice,
|
||||
USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT,
|
||||
UAS_SET_CUR, UAS_SAMPLING_FREQ_CONTROL << 8,
|
||||
address, 3, data, &actualLength);
|
||||
|
||||
TRACE_ALWAYS("set_speed %02x%02x%02x for ep %#x %d: %x\n",
|
||||
data[0], data[1], data[2],
|
||||
address, actualLength, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -398,6 +468,8 @@ status_t
|
||||
Stream::GetBuffers(multi_buffer_list* List)
|
||||
{
|
||||
// TODO: check the available buffers count!
|
||||
if (fAreaSize == 0)
|
||||
return B_NO_INIT;
|
||||
|
||||
int32 startChannel = List->return_playback_channels;
|
||||
buffer_desc** Buffers = List->playback_buffers;
|
||||
@@ -425,8 +497,8 @@ Stream::GetBuffers(multi_buffer_list* List)
|
||||
TypeIFormatDescriptor* format
|
||||
= static_cast<TypeIFormatDescriptor*>(
|
||||
fAlternates[fActiveAlternate]->Format());
|
||||
const ASEndpointDescriptor* endpoint
|
||||
= fAlternates[fActiveAlternate]->Endpoint();
|
||||
// const ASEndpointDescriptor* endpoint
|
||||
// = fAlternates[fActiveAlternate]->Endpoint();
|
||||
|
||||
// [buffer][channel] init buffers
|
||||
for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) {
|
||||
@@ -443,7 +515,7 @@ Stream::GetBuffers(multi_buffer_list* List)
|
||||
Buffers[buffer][channel].base
|
||||
= (char*)(fDescriptors + fDescriptorsCount);
|
||||
// shift for whole buffer if required
|
||||
size_t bufferSize = endpoint->fMaxPacketSize
|
||||
size_t bufferSize = fPacketSize/*endpoint->fMaxPacketSize*/
|
||||
* (fDescriptorsCount / kSamplesBufferCount);
|
||||
Buffers[buffer][channel].base += buffer * bufferSize;
|
||||
// shift for channel if required
|
||||
@@ -467,29 +539,6 @@ Stream::GetBuffers(multi_buffer_list* List)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
int32
|
||||
Stream::InterruptHandler(uint32 SignaledChannelsMask)
|
||||
{
|
||||
uint32 ChannelMask = 1 << fHWChannel;
|
||||
if ((SignaledChannelsMask & ChannelMask) == 0) {
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
uint32 CurrentSamplePositionFlag = fDevice->ReadPCI32(TrCurSPFBReg);
|
||||
|
||||
fRealTime = system_time();
|
||||
fFramesCount += fBufferSize;
|
||||
fBufferCycle = ((CurrentSamplePositionFlag & ChannelMask) == ChannelMask) ? 1 : 0;
|
||||
|
||||
fCSP = CurrentSamplePositionFlag;
|
||||
|
||||
release_sem_etc(fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}*/
|
||||
|
||||
|
||||
bool
|
||||
Stream::ExchangeBuffer(multi_buffer_info* Info)
|
||||
{
|
||||
@@ -499,12 +548,15 @@ Stream::ExchangeBuffer(multi_buffer_info* Info)
|
||||
return false;
|
||||
}
|
||||
|
||||
Info->played_real_time = system_time();// TODO fRealTime;
|
||||
Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
|
||||
Info->playback_buffer_cycle = fCurrentBuffer;
|
||||
|
||||
fCurrentBuffer++;
|
||||
fCurrentBuffer %= kSamplesBufferCount;
|
||||
if (fIsInput) {
|
||||
Info->recorded_real_time = system_time();// TODO fRealTime;
|
||||
Info->recorded_frames_count += fSamplesCount / kSamplesBufferCount;
|
||||
Info->record_buffer_cycle = fCurrentBuffer;
|
||||
} else {
|
||||
Info->played_real_time = system_time();// TODO fRealTime;
|
||||
Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
|
||||
Info->playback_buffer_cycle = fCurrentBuffer;
|
||||
}
|
||||
|
||||
atomic_add(&fProcessedBuffers, -1);
|
||||
|
||||
|
||||
@@ -62,22 +62,21 @@ protected:
|
||||
uint8 fTerminalID;
|
||||
usb_pipe fStreamEndpoint;
|
||||
bool fIsRunning;
|
||||
/* uint32 fHWChannel;*/
|
||||
area_id fArea;
|
||||
size_t fAreaSize;
|
||||
usb_iso_packet_descriptor* fDescriptors;
|
||||
size_t fDescriptorsCount;
|
||||
size_t fCurrentBuffer;
|
||||
uint32 fStartingFrame;
|
||||
size_t fSamplesCount;
|
||||
size_t fPacketSize;
|
||||
int32 fProcessedBuffers;
|
||||
// void* fBuffersPhysAddress;
|
||||
/* bigtime_t fRealTime;
|
||||
bigtime_t fFramesCount;
|
||||
int32 fBufferCycle;
|
||||
public:
|
||||
uint32 fCSP; */
|
||||
_multi_format fFormat;
|
||||
|
||||
private:
|
||||
status_t _QueueNextTransfer(size_t buffer);
|
||||
status_t _ChooseAlternate();
|
||||
status_t _SetupBuffers();
|
||||
status_t _QueueNextTransfer(size_t buffer, bool start);
|
||||
static void _TransferCallback(void *cookie, int32 status,
|
||||
void *data, uint32 actualLength);
|
||||
void _DumpDescriptors();
|
||||
|
||||
Reference in New Issue
Block a user