1#include <fcntl.h> 2#include <malloc.h> 3#include <math.h> 4#include <stdio.h> 5#include <string.h> 6#include <sys/uio.h> 7#include <unistd.h> 8 9#include <media/Buffer.h> 10#include <media/BufferGroup.h> 11#include <media/ParameterWeb.h> 12#include <media/TimeSource.h> 13 14#include <support/Autolock.h> 15#include <support/Debug.h> 16 17#include "driver_io.h" 18#include "LegacyAudioConsumer.h" 19 20 21LegacyAudioConsumer::LegacyAudioConsumer( BMediaAddOn *addon, const char *name, int32 internal_id ) 22 : BMediaNode( name ), BBufferConsumer( B_MEDIA_RAW_AUDIO ) 23{ 24 mInitStatus = B_NO_INIT; 25 26 mAddOn = addon; 27 28 mId = internal_id; 29 30 mBuffers = NULL; 31 32 mThread = -1; 33 34 mProcessingLatency = 0LL; 35 36 mRunning = false; 37 mConnected = false; 38 39 io_buf1 = NULL; 40 41 AddNodeKind( B_PHYSICAL_OUTPUT ); 42 43 sprintf( device_name, "/dev/audio/old/%s", name ); 44 45 //open the device driver for output 46 fd = open( device_name, O_WRONLY ); 47 48 if ( fd == 0 ) { 49 return; 50 } 51 52 mBuffer_size = 4096; 53 54 io_buf1 = static_cast<audio_buffer_header *>( 55 malloc( 2 * ( sizeof( audio_buffer_header ) + mBuffer_size )) 56 ); 57 58 if ( io_buf1 == NULL ) { 59 close( fd ); 60 return; 61 } 62 63 io_buf2 = reinterpret_cast<audio_buffer_header *>( 64 reinterpret_cast<char *>(const_cast<audio_buffer_header *>( io_buf1 )) 65 + sizeof( audio_buffer_header ) 66 + mBuffer_size); 67 68 io_buf1->reserved_1 = sizeof( audio_buffer_header ) + mBuffer_size; 69 io_buf2->reserved_1 = sizeof( audio_buffer_header ) + mBuffer_size; 70 71 mInitStatus = B_OK; 72 return; 73} 74 75 76LegacyAudioConsumer::~LegacyAudioConsumer() 77{ 78 if ( mInitStatus != B_OK ) { 79 return; 80 } 81 82 /* Clean up */ 83 if ( mConnected ) { 84 Disconnected( mInput.source, mInput.destination ); 85 } 86 87 if ( mRunning ) { 88 HandleStop(); 89 } 90 91 if ( io_buf1 != NULL ) { 92 free( static_cast<void *>(const_cast<audio_buffer_header *>(io_buf1)) ); 93 } 94 95 if ( fd != 0 ) { 96 close( fd ); 97 } 98} 99 100 101/* BMediaNode */ 102 103BMediaAddOn * 104LegacyAudioConsumer::AddOn( int32 *internal_id ) const 105{ 106 if ( internal_id ) { 107 *internal_id = mId; 108 } 109 110 return mAddOn; 111} 112 113 114void 115LegacyAudioConsumer::NodeRegistered() 116{ 117 mInput.destination.port = ControlPort(); 118 mInput.destination.id = 0; 119 120 mInput.source = media_source::null; 121 122 mInput.format.type = B_MEDIA_RAW_AUDIO; 123 mInput.format.u.raw_audio.frame_rate = 44100.0; 124 mInput.format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; 125 mInput.format.u.raw_audio.channel_count = 2; 126 mInput.format.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 127 mInput.format.u.raw_audio.buffer_size = mBuffer_size; 128 129 Run(); 130} 131 132 133status_t 134LegacyAudioConsumer::HandleMessage( int32 message, const void *data, size_t size ) 135{ 136 status_t err = B_OK; 137 138 if ( BBufferConsumer::HandleMessage( message, data, size ) != B_OK ) { 139 if ( ( err = BMediaNode::HandleMessage( message, data, size ) ) != B_OK ) { 140 BMediaNode::HandleBadMessage( message, data, size ); 141 } 142 } 143 144 return err; 145} 146 147 148/* BBufferConsumer */ 149 150status_t 151LegacyAudioConsumer::AcceptFormat( const media_destination &dest, media_format *format ) 152{ 153 if ( format->type != B_MEDIA_RAW_AUDIO ) { 154 return B_MEDIA_BAD_FORMAT; 155 } 156 157 format->u.raw_audio.frame_rate = 44100.0; 158 format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; 159 format->u.raw_audio.channel_count = 2; 160 format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 161 format->u.raw_audio.buffer_size = mBuffer_size; 162 163 return B_OK; 164} 165 166 167status_t 168LegacyAudioConsumer::GetNextInput( int32 *cookie, media_input *out_input ) 169{ 170 if ( *cookie == 0 ) { 171 memcpy( out_input, &mInput , sizeof( media_input ) ); 172 } 173 174 return B_BAD_INDEX; 175} 176 177 178void 179LegacyAudioConsumer::BufferReceived( BBuffer *buffer ) 180{ 181 if ( ! mRunning ) { 182 183 buffer->Recycle(); 184 185 } else { 186 187 media_timed_event event( buffer->Header()->start_time, 188 BTimedEventQueue::B_HANDLE_BUFFER, 189 buffer, 190 BTimedEventQueue::B_RECYCLE_BUFFER ); 191 192 EventQueue()->AddEvent( event ); 193 194 } 195} 196 197 198void 199LegacyAudioConsumer::ProducerDataStatus( const media_destination &for_whom, int32 status, 200 bigtime_t at_media_time ) 201{ 202} 203 204 205status_t 206LegacyAudioConsumer::GetLatencyFor( const media_destination &for_whom, bigtime_t *out_latency, 207 media_node_id *out_timesource ) 208{ 209 *out_latency = mBuffer_size * 10000 / 4 / 441; 210 return B_OK; 211} 212 213 214status_t 215LegacyAudioConsumer::Connected( const media_source &producer, const media_destination &where, 216 const media_format &with_format, media_input *out_input ) 217{ 218 mInput.source = producer; 219 //mInput.format = with_format; 220 mInput.node = Node(); 221 strcpy( mInput.name, "Legacy Audio Consumer" ); 222 223 mBuffers = new BBufferGroup; 224 225 uint32 dummy_data = 0; 226 int32 change_tag = 1; 227 228 BBufferConsumer::SetOutputBuffersFor( producer, mDest, mBuffers, static_cast<void *>( &dummy_data ), 229 &change_tag, true ); 230 231 mConnected = true; 232 return B_OK; 233} 234 235 236void 237LegacyAudioConsumer::Disconnected( const media_source &producer, const media_destination &where ) 238{ 239 if ( mConnected ) { 240 delete mBuffers; 241 mInput.source = media_source::null; 242 mConnected = false; 243 } 244} 245 246status_t 247LegacyAudioConsumer::FormatChanged( const media_source &producer, const media_destination &consumer, 248 int32 change_tag, const media_format &format ) 249{ 250 return B_OK; 251} 252 253 254/* BMediaEventLooper */ 255 256void 257LegacyAudioConsumer::HandleEvent( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent ) 258{ 259 switch(event->type) { 260 case BTimedEventQueue::B_START: 261 HandleStart( event->event_time ); 262 break; 263 264 case BTimedEventQueue::B_STOP: 265 HandleStop(); 266 break; 267 268 case BTimedEventQueue::B_WARP: 269 HandleTimeWarp( event->bigdata ); 270 break; 271 272 case BTimedEventQueue::B_SEEK: 273 HandleSeek( event->bigdata ); 274 break; 275 276 case BTimedEventQueue::B_HANDLE_BUFFER: 277 HandleBuffer( static_cast<BBuffer *>( event->pointer ) ); 278 break; 279 280 case BTimedEventQueue::B_DATA_STATUS: 281 case BTimedEventQueue::B_PARAMETER: 282 default: 283 break; //HandleEvent: Unhandled event 284 } 285} 286 287 288/* LegacyAudioConsumer */ 289 290void 291LegacyAudioConsumer::HandleStart( bigtime_t performance_time ) 292{ 293 if ( mRunning ) { 294 return; 295 } 296 297 mPerformanceTimeBase = performance_time; 298 299 //allocate buffer available semaphore 300 mBuffer_avail = create_sem( 0, "legacy audio out buffer avail" ); 301 302 if ( mBuffer_avail < B_OK ) { 303 goto init_err1; 304 } 305 306 //allocate buffer free semaphore 307 mBuffer_free = create_sem( 1, "legacy audio out buffer free" ); 308 309 if ( mBuffer_free < B_OK ) { 310 goto init_err2; 311 } 312 313 //allocate output completion semaphore 314 mBuffer_waitIO = create_sem( 1, "legacy audio out waitIO" ); 315 316 if ( mBuffer_waitIO < B_OK ) { 317 goto init_err3; 318 } 319 320 //tell the driver about the playback completion semaphore 321 DRIVER_SET_PLAYBACK_COMPLETION_SEM( &mBuffer_waitIO, 0 ); 322 323 mThread = spawn_thread( _run_thread_, "legacy audio output", B_REAL_TIME_PRIORITY, this ); 324 325 if ( mThread < B_OK ) { 326 goto init_err4; 327 } 328 329 io_buf = io_buf1; 330 331 resume_thread( mThread ); 332 333 mRunning = true; 334 return; 335 336init_err4: 337 delete_sem( mBuffer_waitIO ); 338 339init_err3: 340 delete_sem( mBuffer_free ); 341 342init_err2: 343 delete_sem( mBuffer_avail ); 344 345init_err1: 346 return; 347} 348 349 350void 351LegacyAudioConsumer::HandleStop() 352{ 353 if ( ! mRunning ) { 354 return; 355 } 356 357 delete_sem( mBuffer_avail ); 358 delete_sem( mBuffer_free ); 359 delete_sem( mBuffer_waitIO ); 360 wait_for_thread( mThread, &mThread ); 361 362 mRunning = false; 363} 364 365 366void 367LegacyAudioConsumer::HandleTimeWarp( bigtime_t performance_time ) 368{ 369 mPerformanceTimeBase = performance_time; 370} 371 372 373void 374LegacyAudioConsumer::HandleSeek( bigtime_t performance_time ) 375{ 376 mPerformanceTimeBase = performance_time; 377} 378 379 380void 381LegacyAudioConsumer::HandleBuffer( BBuffer *buffer ) 382{ 383 audio_buffer_header *buf; 384 385 //wait for free buffer 386 acquire_sem( mBuffer_free ); 387 388 //avoid buffer currently in use 389 buf = const_cast<audio_buffer_header *>( ( io_buf == io_buf2 ) ? io_buf1 : io_buf2 ); 390 391 //prepare buffer 392 memcpy( reinterpret_cast<char *>( buf ) + sizeof( audio_buffer_header ), buffer->Data(), buffer->SizeUsed() ); 393 394 //tell the io thread a new buffer is ready 395 release_sem( mBuffer_avail ); 396} 397 398 399int32 400LegacyAudioConsumer::_run_thread_( void *data ) 401{ 402 return static_cast<LegacyAudioConsumer *>( data )->RunThread(); 403} 404 405 406int32 407LegacyAudioConsumer::RunThread() 408{ 409 while ( 1 ) { 410 411 //wait for next buffer 412 if ( acquire_sem( mBuffer_avail ) == B_BAD_SEM_ID ) { 413 return B_OK; 414 } 415 416 //send buffer 417 DRIVER_WRITE_BUFFER( io_buf, 0 ); 418 419 //wait for IO 420 if ( acquire_sem( mBuffer_waitIO ) == B_BAD_SEM_ID ) { 421 return B_OK; 422 } 423 424 io_buf = ( io_buf == io_buf2 ) ? io_buf1 : io_buf2; 425 426 //mark buffer free 427 release_sem( mBuffer_free ); 428 } 429 430 return B_OK; 431} 432