added null_audio driver from Bek, HOST team. Thanks.
Applied some style fixes. It's not recognized as a fallback driver. We might also consider a simple userland BufferConsumer/BufferProducer. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22299 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
c32beda5c4
commit
57cba4584f
@ -6,6 +6,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers audio echo ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio emuxki ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio hda ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio module_driver ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio null ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio sb16 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio sis7018 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers audio usb_audio ;
|
||||
|
12
src/add-ons/kernel/drivers/audio/null/Jamfile
Normal file
12
src/add-ons/kernel/drivers/audio/null/Jamfile
Normal file
@ -0,0 +1,12 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers audio null ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders media ;
|
||||
|
||||
KernelAddon null_audio :
|
||||
driver.c
|
||||
null_hardware.c
|
||||
null_multi.c
|
||||
;
|
||||
|
132
src/add-ons/kernel/drivers/audio/null/driver.c
Normal file
132
src/add-ons/kernel/drivers/audio/null/driver.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2007 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Bek, host.haiku@gmx.de
|
||||
*/
|
||||
#include "driver.h"
|
||||
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||
device_t device;
|
||||
|
||||
|
||||
status_t
|
||||
init_hardware(void)
|
||||
{
|
||||
dprintf("null_audio: %s\n", __func__);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
init_driver(void)
|
||||
{
|
||||
dprintf("null_audio: %s\n", __func__);
|
||||
device.running = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const char**
|
||||
publish_devices(void)
|
||||
{
|
||||
static const char* published_paths[] = {
|
||||
MULTI_AUDIO_DEV_PATH "/null/0",
|
||||
NULL
|
||||
};
|
||||
dprintf("null_audio: %s\n", __func__);
|
||||
|
||||
return published_paths;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
null_audio_open (const char *name, uint32 flags, void** cookie)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
*cookie = &device;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
null_audio_read (void* cookie, off_t a, void* b, size_t* num_bytes)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
// Audio drivers are not supposed to return anything
|
||||
// inside here
|
||||
*num_bytes = 0;
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
null_audio_write (void* cookie, off_t a, const void* b, size_t* num_bytes)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
// Audio drivers are not supposed to return anything
|
||||
// inside here
|
||||
*num_bytes = 0;
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
null_audio_control (void* cookie, uint32 op, void* arg, size_t len)
|
||||
{
|
||||
//dprintf("null_audio: %s\n" , __func__ );
|
||||
// In case we have a valid cookie, initialized
|
||||
// the driver and hardware connection properly
|
||||
// Simply pass through to the multi audio hooks
|
||||
if (cookie)
|
||||
return multi_audio_control(cookie, op, arg, len);
|
||||
else
|
||||
dprintf("null_audio: %s called without cookie\n" , __func__);
|
||||
|
||||
// Return error in case we have no valid setup
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
null_audio_close (void* cookie)
|
||||
{
|
||||
device_t* device = (device_t*) cookie;
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
if (device && device->running)
|
||||
null_stop_hardware(device);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
null_audio_free (void* cookie)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
device_hooks driver_hooks = {
|
||||
null_audio_open,
|
||||
null_audio_close,
|
||||
null_audio_free,
|
||||
null_audio_control,
|
||||
null_audio_read,
|
||||
null_audio_write
|
||||
};
|
||||
|
||||
|
||||
device_hooks*
|
||||
find_device(const char* name)
|
||||
{
|
||||
return &driver_hooks;
|
||||
}
|
||||
|
60
src/add-ons/kernel/drivers/audio/null/driver.h
Normal file
60
src/add-ons/kernel/drivers/audio/null/driver.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2007 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef NULL_AUDIO_DRIVER_H
|
||||
#define NULL_AUDIO_DRIVER_H
|
||||
|
||||
#include <drivers/driver_settings.h>
|
||||
#include <drivers/Drivers.h>
|
||||
#include <drivers/KernelExport.h>
|
||||
|
||||
#include <hmulti_audio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FRAMES_PER_BUFFER 1024
|
||||
#define MULTI_AUDIO_BASE_ID 1024
|
||||
#define MULTI_AUDIO_DEV_PATH "audio/hmulti"
|
||||
#define MULTI_AUDIO_MASTER_ID 0
|
||||
#define STRMINBUF 2
|
||||
#define STRMAXBUF 2
|
||||
|
||||
typedef struct {
|
||||
spinlock lock;
|
||||
int bits;
|
||||
|
||||
void* buffers[STRMAXBUF];
|
||||
uint32 num_buffers;
|
||||
uint32 num_channels;
|
||||
uint32 format;
|
||||
uint32 rate;
|
||||
|
||||
uint32 buffer_length;
|
||||
sem_id buffer_ready_sem;
|
||||
uint32 frames_count;
|
||||
uint32 buffer_cycle;
|
||||
bigtime_t real_time;
|
||||
|
||||
area_id buffer_area;
|
||||
} device_stream_t;
|
||||
|
||||
typedef struct {
|
||||
device_stream_t playback_stream;
|
||||
device_stream_t record_stream;
|
||||
|
||||
thread_id interrupt_thread;
|
||||
bool running;
|
||||
} device_t;
|
||||
|
||||
extern device_hooks driver_hooks;
|
||||
int32 format_to_sample_size(uint32 format);
|
||||
|
||||
status_t multi_audio_control(void* cookie, uint32 op, void* arg, size_t len);
|
||||
|
||||
status_t null_hw_create_virtual_buffers(device_stream_t* stream, const char* name);
|
||||
status_t null_start_hardware(device_t* device);
|
||||
void null_stop_hardware(device_t* device);
|
||||
|
||||
#endif /* NULL_AUDIO_DRIVER_H */
|
||||
|
123
src/add-ons/kernel/drivers/audio/null/null_hardware.c
Normal file
123
src/add-ons/kernel/drivers/audio/null/null_hardware.c
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2007 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Bek, host.haiku@gmx.de
|
||||
*/
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
status_t
|
||||
null_hw_create_virtual_buffers(device_stream_t* stream, const char* name)
|
||||
{
|
||||
int i;
|
||||
int buffer_size;
|
||||
int area_size;
|
||||
uint8* buffer;
|
||||
status_t result;
|
||||
physical_entry pe;
|
||||
|
||||
buffer_size = stream->num_channels
|
||||
* format_to_sample_size(stream->format)
|
||||
* stream->buffer_length;
|
||||
buffer_size = (buffer_size + 127) & (~127);
|
||||
|
||||
area_size = buffer_size * stream->num_buffers;
|
||||
area_size = (area_size + B_PAGE_SIZE - 1) & (~(B_PAGE_SIZE -1));
|
||||
|
||||
stream->buffer_area = create_area("null_audio_buffers", (void**)&buffer,
|
||||
B_ANY_KERNEL_ADDRESS, area_size,
|
||||
B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
|
||||
if (stream->buffer_area < B_OK)
|
||||
return stream->buffer_area;
|
||||
|
||||
// Get the correct address for setting up the buffers
|
||||
// pointers being passed back to userland
|
||||
result = get_memory_map(buffer, area_size, &pe, 1);
|
||||
if (result != B_OK) {
|
||||
delete_area(stream->buffer_area);
|
||||
return result;
|
||||
}
|
||||
|
||||
for (i=0; i < stream->num_buffers; i++) {
|
||||
stream->buffers[i] = buffer + (i*buffer_size);
|
||||
}
|
||||
|
||||
stream->buffer_ready_sem = create_sem(0, name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
null_fake_interrupt(void* cookie)
|
||||
{
|
||||
// This thread is supposed to fake the interrupt
|
||||
// handling done in communication with the
|
||||
// hardware usually. What it does is nearly the
|
||||
// same like all soundrivers, get the interrupt
|
||||
// exchange the buffer pointer and update the
|
||||
// time information. Instead of exiting, we wait
|
||||
// until the next fake interrupt appears.
|
||||
int sleepTime;
|
||||
device_t* device = (device_t*) cookie;
|
||||
int sampleRate;
|
||||
|
||||
switch (device->playback_stream.rate) {
|
||||
case B_SR_48000:
|
||||
sampleRate = 48000;
|
||||
break;
|
||||
case B_SR_44100:
|
||||
default:
|
||||
sampleRate = 44100;
|
||||
break;
|
||||
}
|
||||
|
||||
// The time between until we get a new valid buffer
|
||||
// from our soundcard: buffer_length / samplerate
|
||||
sleepTime = (device->playback_stream.buffer_length*1000) / sampleRate;
|
||||
|
||||
while (device->running) {
|
||||
cpu_status status;
|
||||
status = disable_interrupts();
|
||||
acquire_spinlock(&device->playback_stream.lock);
|
||||
device->playback_stream.real_time = system_time();
|
||||
device->playback_stream.frames_count += device->playback_stream.buffer_length;
|
||||
device->playback_stream.buffer_cycle = (device->playback_stream.buffer_cycle +1) % device->playback_stream.num_buffers;
|
||||
release_spinlock(&device->playback_stream.lock);
|
||||
|
||||
// TODO: Create a simple sinus wave, so that recording from
|
||||
// the virtual device actually returns something useful
|
||||
acquire_spinlock(&device->record_stream.lock);
|
||||
device->record_stream.real_time = device->playback_stream.real_time;
|
||||
device->record_stream.frames_count += device->record_stream.buffer_length;
|
||||
device->record_stream.buffer_cycle = (device->record_stream.buffer_cycle +1) % device->record_stream.num_buffers;
|
||||
release_spinlock(&device->record_stream.lock);
|
||||
|
||||
restore_interrupts(status);
|
||||
|
||||
release_sem_etc(device->playback_stream.buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
release_sem_etc(device->record_stream.buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
snooze(sleepTime);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
null_start_hardware(device_t* device)
|
||||
{
|
||||
dprintf("null_audio: %s spawning fake interrupter\n", __func__);
|
||||
device->running = true;
|
||||
device->interrupt_thread = spawn_kernel_thread(null_fake_interrupt, "null_audio interrupter",
|
||||
B_REAL_TIME_PRIORITY, (void*)device);
|
||||
return resume_thread(device->interrupt_thread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
null_stop_hardware(device_t* device)
|
||||
{
|
||||
device->running = false;
|
||||
}
|
||||
|
352
src/add-ons/kernel/drivers/audio/null/null_multi.c
Normal file
352
src/add-ons/kernel/drivers/audio/null/null_multi.c
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 2007 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Bek, host.haiku@gmx.de
|
||||
*/
|
||||
#include "driver.h"
|
||||
|
||||
// Convenience function to determine the byte count
|
||||
// of a sample for a given format.
|
||||
// Note: Currently null_audio only supports 16 bit,
|
||||
// but that is supposed to change later
|
||||
int32
|
||||
format_to_sample_size(uint32 format)
|
||||
{
|
||||
switch(format) {
|
||||
case B_FMT_8BIT_S:
|
||||
return 1;
|
||||
case B_FMT_16BIT:
|
||||
return 2;
|
||||
|
||||
case B_FMT_18BIT:
|
||||
case B_FMT_24BIT:
|
||||
case B_FMT_32BIT:
|
||||
case B_FMT_FLOAT:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
multi_channel_info channel_descriptions[] = {
|
||||
{ 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
|
||||
{ 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
|
||||
{ 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
|
||||
{ 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
|
||||
{ 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
|
||||
{ 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
|
||||
{ 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
|
||||
{ 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
|
||||
};
|
||||
|
||||
|
||||
static status_t
|
||||
get_description(void* cookie, multi_description* data)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
data->interface_version = B_CURRENT_INTERFACE_VERSION;
|
||||
data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
|
||||
|
||||
strcpy(data->friendly_name,"Virtual Audio (null_audio)");
|
||||
strcpy(data->vendor_info,"Host/Haiku");
|
||||
|
||||
data->output_channel_count = 2;
|
||||
data->input_channel_count = 2;
|
||||
data->output_bus_channel_count = 2;
|
||||
data->input_bus_channel_count = 2;
|
||||
data->aux_bus_channel_count = 0;
|
||||
|
||||
if (data->request_channel_count >= (int)(sizeof(channel_descriptions) / sizeof(channel_descriptions[0]))) {
|
||||
memcpy(data->channels,&channel_descriptions,sizeof(channel_descriptions));
|
||||
}
|
||||
|
||||
data->output_rates = B_SR_44100;
|
||||
data->input_rates = B_SR_44100;
|
||||
|
||||
data->max_cvsr_rate = 0;
|
||||
data->min_cvsr_rate = 0;
|
||||
|
||||
data->output_formats = B_FMT_16BIT;
|
||||
data->input_formats = B_FMT_16BIT;
|
||||
data->lock_sources = B_MULTI_LOCK_INTERNAL;
|
||||
data->timecode_sources = 0;
|
||||
data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
|
||||
data->start_latency = 30000;
|
||||
|
||||
strcpy(data->control_panel,"");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_enabled_channels(void* cookie, multi_channel_enable* data)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
// By default we say, that all channels are enabled
|
||||
// and that this cannot be changed
|
||||
B_SET_CHANNEL(data->enable_bits, 0, true);
|
||||
B_SET_CHANNEL(data->enable_bits, 1, true);
|
||||
B_SET_CHANNEL(data->enable_bits, 2, true);
|
||||
B_SET_CHANNEL(data->enable_bits, 3, true);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
set_global_format(device_t* device, multi_format_info* data)
|
||||
{
|
||||
// The media kit asks us to set our streams
|
||||
// according to its settings
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
device->playback_stream.format = data->output.format;
|
||||
device->playback_stream.rate = data->output.rate;
|
||||
|
||||
device->record_stream.format = data->input.format;
|
||||
device->record_stream.rate = data->input.rate;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_global_format(device_t* device, multi_format_info* data)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
// Zero latency is unlikely to happen, so we fake some
|
||||
// additional latency
|
||||
data->output_latency = 30;
|
||||
data->input_latency = 30;
|
||||
data->timecode_kind = 0;
|
||||
|
||||
data->output.format = device->playback_stream.format;
|
||||
data->output.rate = device->playback_stream.rate;
|
||||
data->input.format = device->record_stream.format;
|
||||
data->input.rate = device->record_stream.rate;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
create_group_control(multi_mix_control* multi, int32 idx, int32 parent, int32 string, const char* name)
|
||||
{
|
||||
multi->id = MULTI_AUDIO_BASE_ID + idx;
|
||||
multi->parent = parent;
|
||||
multi->flags = B_MULTI_MIX_GROUP;
|
||||
multi->master = MULTI_AUDIO_MASTER_ID;
|
||||
multi->string = string;
|
||||
if(name)
|
||||
strcpy(multi->name, name);
|
||||
|
||||
return multi->id;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
list_mix_controls(device_t* device, multi_mix_control_info * data)
|
||||
{
|
||||
int32 parent;
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
|
||||
parent = create_group_control(data->controls +0, 0, 0, 0, "Record");
|
||||
parent = create_group_control(data->controls +1, 1, 0, 0, "Playback");
|
||||
data->control_count = 2;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
list_mix_connections(void* cookie, multi_mix_connection_info* connection_info)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
list_mix_channels(void* cookie, multi_mix_channel_info* channel_info)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_buffers(device_t* device, multi_buffer_list* data)
|
||||
{
|
||||
uint32 playback_sample_size = format_to_sample_size(device->playback_stream.format);
|
||||
uint32 record_sample_size = format_to_sample_size(device->record_stream.format);
|
||||
uint32 cidx, bidx;
|
||||
status_t result;
|
||||
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
|
||||
/* Workaround for Haiku multi_audio API, since it prefers to let the driver pick
|
||||
values, while the BeOS multi_audio actually gives the user's defaults. */
|
||||
if (data->request_playback_buffers > STRMAXBUF
|
||||
|| data->request_playback_buffers < STRMINBUF) {
|
||||
data->request_playback_buffers = STRMINBUF;
|
||||
}
|
||||
|
||||
if (data->request_record_buffers > STRMAXBUF
|
||||
|| data->request_record_buffers < STRMINBUF) {
|
||||
data->request_record_buffers = STRMINBUF;
|
||||
}
|
||||
|
||||
if (data->request_playback_buffer_size == 0)
|
||||
data->request_playback_buffer_size = FRAMES_PER_BUFFER;
|
||||
|
||||
if (data->request_record_buffer_size == 0)
|
||||
data->request_record_buffer_size = FRAMES_PER_BUFFER;
|
||||
|
||||
/* ... from here on, we can assume again that a reasonable request is being made */
|
||||
|
||||
data->flags = 0;
|
||||
|
||||
// Copy the requested settings into the streams
|
||||
// and initialize the virtual buffers properly
|
||||
device->playback_stream.num_buffers = data->request_playback_buffers;
|
||||
device->playback_stream.num_channels = data->request_playback_channels;
|
||||
device->playback_stream.buffer_length = data->request_playback_buffer_size;
|
||||
if ((result = null_hw_create_virtual_buffers(&device->playback_stream, "null_audio_playback_sem")) != B_OK) {
|
||||
dprintf("null_audio %s: Error setting up playback buffers (%s)\n", __func__, strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
device->record_stream.num_buffers = data->request_record_buffers;
|
||||
device->record_stream.num_channels = data->request_record_channels;
|
||||
device->record_stream.buffer_length = data->request_record_buffer_size;
|
||||
if ((result = null_hw_create_virtual_buffers(&device->record_stream, "null_audio_record_sem")) != B_OK) {
|
||||
dprintf("null_audio %s: Error setting up recording buffers (%s)\n", __func__, strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Setup data structure for multi_audio API... */
|
||||
data->return_playback_buffers = data->request_playback_buffers;
|
||||
data->return_playback_channels = data->request_playback_channels;
|
||||
data->return_playback_buffer_size = data->request_playback_buffer_size;
|
||||
|
||||
for (bidx=0; bidx < data->return_playback_buffers; bidx++) {
|
||||
for (cidx=0; cidx < data->return_playback_channels; cidx++) {
|
||||
data->playback_buffers[bidx][cidx].base = device->playback_stream.buffers[bidx] + (playback_sample_size * cidx);
|
||||
data->playback_buffers[bidx][cidx].stride = playback_sample_size * data->return_playback_channels;
|
||||
}
|
||||
}
|
||||
|
||||
data->return_record_buffers = data->request_record_buffers;
|
||||
data->return_record_channels = data->request_record_channels;
|
||||
data->return_record_buffer_size = data->request_record_buffer_size;
|
||||
|
||||
for (bidx=0; bidx < data->return_record_buffers; bidx++) {
|
||||
for (cidx=0; cidx < data->return_record_channels; cidx++) {
|
||||
data->record_buffers[bidx][cidx].base = device->record_stream.buffers[bidx] + (record_sample_size * cidx);
|
||||
data->record_buffers[bidx][cidx].stride = record_sample_size * data->return_record_channels;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
buffer_exchange(device_t* device, multi_buffer_info* buffer_info)
|
||||
{
|
||||
//dprintf("null_audio: %s\n" , __func__ );
|
||||
static int debug_buffers_exchanged = 0;
|
||||
cpu_status status;
|
||||
status_t result;
|
||||
|
||||
// On first call, we start our fake hardware.
|
||||
// Usually one would jump into his interrupt handler now
|
||||
if (!device->running)
|
||||
null_start_hardware(device);
|
||||
|
||||
result = acquire_sem(device->playback_stream.buffer_ready_sem);
|
||||
if (result != B_OK) {
|
||||
dprintf("null_audio: %s, Could not get playback buffer\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = acquire_sem(device->record_stream.buffer_ready_sem);
|
||||
if (result != B_OK) {
|
||||
dprintf("null_audio: %s, Could not get record buffer\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
status = disable_interrupts();
|
||||
acquire_spinlock(&device->playback_stream.lock);
|
||||
|
||||
buffer_info->playback_buffer_cycle = device->playback_stream.buffer_cycle;
|
||||
buffer_info->played_real_time = device->playback_stream.real_time;
|
||||
buffer_info->played_frames_count = device->playback_stream.frames_count;
|
||||
|
||||
buffer_info->record_buffer_cycle = device->record_stream.buffer_cycle;
|
||||
buffer_info->recorded_real_time = device->record_stream.real_time;
|
||||
buffer_info->recorded_frames_count = device->record_stream.frames_count;
|
||||
|
||||
release_spinlock(&device->playback_stream.lock);
|
||||
restore_interrupts(status);
|
||||
|
||||
debug_buffers_exchanged++;
|
||||
if (((debug_buffers_exchanged % 5000) == 0) ) { //&& debug_buffers_exchanged < 1111) {
|
||||
dprintf("null_audio: %s: %d buffers processed\n", __func__, debug_buffers_exchanged);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
buffer_force_stop(device_t* device)
|
||||
{
|
||||
dprintf("null_audio: %s\n" , __func__ );
|
||||
|
||||
if (device && device->running)
|
||||
null_stop_hardware(device);
|
||||
|
||||
delete_area(device->playback_stream.buffer_area);
|
||||
delete_area(device->record_stream.buffer_area);
|
||||
|
||||
delete_sem(device->playback_stream.buffer_ready_sem);
|
||||
delete_sem(device->record_stream.buffer_ready_sem);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MULTI_GET_DESCRIPTION: return get_description(cookie, arg);
|
||||
case B_MULTI_GET_EVENT_INFO: return B_ERROR;
|
||||
case B_MULTI_SET_EVENT_INFO: return B_ERROR;
|
||||
case B_MULTI_GET_EVENT: return B_ERROR;
|
||||
case B_MULTI_GET_ENABLED_CHANNELS: return get_enabled_channels(cookie, arg);
|
||||
case B_MULTI_SET_ENABLED_CHANNELS: return B_OK;
|
||||
case B_MULTI_GET_GLOBAL_FORMAT: return get_global_format(cookie, arg);
|
||||
case B_MULTI_SET_GLOBAL_FORMAT: return set_global_format(cookie, arg);
|
||||
case B_MULTI_GET_CHANNEL_FORMATS: return B_ERROR;
|
||||
case B_MULTI_SET_CHANNEL_FORMATS: return B_ERROR;
|
||||
case B_MULTI_GET_MIX: return B_ERROR;
|
||||
case B_MULTI_SET_MIX: return B_ERROR;
|
||||
case B_MULTI_LIST_MIX_CHANNELS: return list_mix_channels(cookie, arg);
|
||||
case B_MULTI_LIST_MIX_CONTROLS: return list_mix_controls(cookie, arg);
|
||||
case B_MULTI_LIST_MIX_CONNECTIONS: return list_mix_connections(cookie, arg);
|
||||
case B_MULTI_GET_BUFFERS: return get_buffers(cookie, arg);
|
||||
case B_MULTI_SET_BUFFERS: return B_ERROR;
|
||||
case B_MULTI_SET_START_TIME: return B_ERROR;
|
||||
case B_MULTI_BUFFER_EXCHANGE: return buffer_exchange(cookie, arg);
|
||||
case B_MULTI_BUFFER_FORCE_STOP: return buffer_force_stop(cookie);
|
||||
}
|
||||
|
||||
dprintf("null_audio: %s - unknown op\n" , __func__);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user