From 2cc4703b91929ece9a3d95942a37363ff32344c7 Mon Sep 17 00:00:00 2001 From: Siarzhuk Zharski Date: Mon, 28 May 2012 18:14:05 +0200 Subject: [PATCH] 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... --- .../usb_audio/AudioStreamingInterface.cpp | 227 ++++++++++-- .../audio/usb_audio/AudioStreamingInterface.h | 14 +- .../kernel/drivers/audio/usb_audio/Device.cpp | 43 ++- .../kernel/drivers/audio/usb_audio/Device.h | 7 +- .../kernel/drivers/audio/usb_audio/Stream.cpp | 342 ++++++++++-------- .../kernel/drivers/audio/usb_audio/Stream.h | 15 +- 6 files changed, 447 insertions(+), 201 deletions(-) diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp index 0c9114003a..653dfaedc4 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.cpp @@ -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(Format()); + + if (format == NULL) { + TRACE_ALWAYS("Format not set for active alternate\n"); + return B_NO_INIT; + } + + Vector& 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(Format()); + + if (format == NULL) { + TRACE_ALWAYS("Format not set for active alternate\n"); + return 0; + } + + uint32 rates = 0; + Vector& 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(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( 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; diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h index 5e89f5ba51..0815c9e613 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/AudioStreamingInterface.h @@ -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; }; diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp index 16000ab376..8bc20553fd 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Device.cpp @@ -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); diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Device.h b/src/add-ons/kernel/drivers/audio/usb_audio/Device.h index e40991d184..facf3897a3 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Device.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Device.h @@ -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; diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp index 9ea21dcb4c..6bf20f03a1 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.cpp @@ -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(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(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( + 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(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( 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); diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h index 960ef9cac8..927e08b269 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Stream.h @@ -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();