comparison libao2/ao_macosx.c @ 14769:e701873aa8ca

rids ao_macosx of the buffer mutex by using the same buffering scheme as ao_sdl - Patch by Reimar Doffinger
author nplourde
date Tue, 22 Feb 2005 20:54:31 +0000
parents 38572280e8e7
children 21f44596f356
comparison
equal deleted inserted replaced
14768:662a391e4901 14769:e701873aa8ca
72 /* CoreAudio */ 72 /* CoreAudio */
73 AudioDeviceID outputDeviceID; 73 AudioDeviceID outputDeviceID;
74 AudioStreamBasicDescription outputStreamBasicDescription; 74 AudioStreamBasicDescription outputStreamBasicDescription;
75 75
76 /* Ring-buffer */ 76 /* Ring-buffer */
77 pthread_mutex_t buffer_mutex; /* mutex covering buffer variables */ 77 /* does not need explicit synchronization, but needs to allocate
78 78 * (num_chunks + 1) * chunk_size memory to store num_chunks * chunk_size
79 unsigned char *buffer[NUM_BUFS]; 79 * data */
80 unsigned int buffer_len; 80 unsigned char *buffer;
81 unsigned int buffer_len; ///< must always be (num_chunks + 1) * chunk_size
82 unsigned int num_chunks;
83 unsigned int chunk_size;
81 84
82 unsigned int buf_read;
83 unsigned int buf_write;
84 unsigned int buf_read_pos; 85 unsigned int buf_read_pos;
85 unsigned int buf_write_pos; 86 unsigned int buf_write_pos;
86 int full_buffers;
87 int buffered_bytes;
88 } ao_macosx_t; 87 } ao_macosx_t;
89 88
90 static ao_macosx_t *ao; 89 static ao_macosx_t *ao;
91 90
92 /* General purpose Ring-buffering routines */ 91 /**
93 static int write_buffer(unsigned char* data,int len){ 92 * \brief return number of free bytes in the buffer
94 int len2=0; 93 * may only be called by mplayer's thread
95 int x; 94 * \return minimum number of free bytes in buffer, value may change between
96 95 * two immediately following calls, and the real number of free bytes
97 while(len>0){ 96 * might actually be larger!
98 if(ao->full_buffers==NUM_BUFS) { 97 */
99 ao_msg(MSGT_AO,MSGL_V, "Buffer overrun\n"); 98 static int buf_free() {
100 break; 99 int free = ao->buf_read_pos - ao->buf_write_pos - ao->chunk_size;
101 } 100 if (free < 0) free += ao->buffer_len;
102 101 return free;
103 x=ao->buffer_len-ao->buf_write_pos; 102 }
104 if(x>len) x=len; 103
105 memcpy(ao->buffer[ao->buf_write]+ao->buf_write_pos,data+len2,x); 104 /**
106 105 * \brief return number of buffered bytes
107 /* accessing common variables, locking mutex */ 106 * may only be called by playback thread
108 pthread_mutex_lock(&ao->buffer_mutex); 107 * \return minimum number of buffered bytes, value may change between
109 len2+=x; len-=x; 108 * two immediately following calls, and the real number of buffered bytes
110 ao->buffered_bytes+=x; ao->buf_write_pos+=x; 109 * might actually be larger!
111 if(ao->buf_write_pos>=ao->buffer_len) { 110 */
112 /* block is full, find next! */ 111 static int buf_used() {
113 ao->buf_write=(ao->buf_write+1)%NUM_BUFS; 112 int used = ao->buf_write_pos - ao->buf_read_pos;
114 ++ao->full_buffers; 113 if (used < 0) used += ao->buffer_len;
115 ao->buf_write_pos=0; 114 return used;
116 } 115 }
117 pthread_mutex_unlock(&ao->buffer_mutex); 116
117 /**
118 * \brief add data to ringbuffer
119 */
120 static int write_buffer(unsigned char* data, int len){
121 int first_len = ao->buffer_len - ao->buf_write_pos;
122 int free = buf_free();
123 if (len > free) len = free;
124 if (first_len > len) first_len = len;
125 // till end of buffer
126 memcpy (&ao->buffer[ao->buf_write_pos], data, first_len);
127 if (len > first_len) { // we have to wrap around
128 // remaining part from beginning of buffer
129 memcpy (ao->buffer, &data[first_len], len - first_len);
118 } 130 }
119 131 ao->buf_write_pos = (ao->buf_write_pos + len) % ao->buffer_len;
120 return len2; 132 return len;
121 } 133 }
122 134
135 /**
136 * \brief remove data from ringbuffer
137 */
123 static int read_buffer(unsigned char* data,int len){ 138 static int read_buffer(unsigned char* data,int len){
124 int len2=0; 139 int first_len = ao->buffer_len - ao->buf_read_pos;
125 int x; 140 int buffered = buf_used();
126 141 if (len > buffered) len = buffered;
127 while(len>0){ 142 if (first_len > len) first_len = len;
128 if(ao->full_buffers==0) { 143 // till end of buffer
129 ao_msg(MSGT_AO,MSGL_V, "Buffer underrun\n"); 144 memcpy (data, &ao->buffer[ao->buf_read_pos], first_len);
130 break; 145 if (len > first_len) { // we have to wrap around
131 } 146 // remaining part from beginning of buffer
132 147 memcpy (&data[first_len], ao->buffer, len - first_len);
133 x=ao->buffer_len-ao->buf_read_pos;
134 if(x>len) x=len;
135 memcpy(data+len2,ao->buffer[ao->buf_read]+ao->buf_read_pos,x);
136 len2+=x; len-=x;
137
138 /* accessing common variables, locking mutex */
139 pthread_mutex_lock(&ao->buffer_mutex);
140 ao->buffered_bytes-=x; ao->buf_read_pos+=x;
141 if(ao->buf_read_pos>=ao->buffer_len){
142 /* block is empty, find next! */
143 ao->buf_read=(ao->buf_read+1)%NUM_BUFS;
144 --ao->full_buffers;
145 ao->buf_read_pos=0;
146 }
147 pthread_mutex_unlock(&ao->buffer_mutex);
148 } 148 }
149 149 ao->buf_read_pos = (ao->buf_read_pos + len) % ao->buffer_len;
150 150 return len;
151 return len2;
152 } 151 }
153 152
154 /* end ring buffer stuff */ 153 /* end ring buffer stuff */
155 154
156 /* The function that the CoreAudio thread calls when it wants more data */ 155 /* The function that the CoreAudio thread calls when it wants more data */
157 static OSStatus audioDeviceIOProc(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData) 156 static OSStatus audioDeviceIOProc(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData)
158 { 157 {
159 outOutputData->mBuffers[0].mDataByteSize = 158 outOutputData->mBuffers[0].mDataByteSize =
160 read_buffer((char *)outOutputData->mBuffers[0].mData, ao->buffer_len); 159 read_buffer((char *)outOutputData->mBuffers[0].mData, ao->chunk_size);
161 160
162 return 0; 161 return 0;
163 } 162 }
164 163
165 164
244 int rc; 243 int rc;
245 int i; 244 int i;
246 245
247 ao = (ao_macosx_t *)malloc(sizeof(ao_macosx_t)); 246 ao = (ao_macosx_t *)malloc(sizeof(ao_macosx_t));
248 247
249 /* initialise mutex */
250 pthread_mutex_init(&ao->buffer_mutex, NULL);
251 pthread_mutex_unlock(&ao->buffer_mutex);
252
253 /* get default output device */ 248 /* get default output device */
254 propertySize = sizeof(ao->outputDeviceID); 249 propertySize = sizeof(ao->outputDeviceID);
255 status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &(ao->outputDeviceID)); 250 status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &(ao->outputDeviceID));
256 if (status) { 251 if (status) {
257 ao_msg(MSGT_AO,MSGL_WARN, 252 ao_msg(MSGT_AO,MSGL_WARN,
376 status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &ao->outputStreamBasicDescription); 371 status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &ao->outputStreamBasicDescription);
377 print_format("final: ",&ao->outputStreamBasicDescription); 372 print_format("final: ",&ao->outputStreamBasicDescription);
378 373
379 /* get requested buffer length */ 374 /* get requested buffer length */
380 // TODO: set NUM_BUFS dinamically, based on buffer size! 375 // TODO: set NUM_BUFS dinamically, based on buffer size!
381 propertySize = sizeof(ao->buffer_len); 376 propertySize = sizeof(ao->chunk_size);
382 status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyBufferSize, &propertySize, &ao->buffer_len); 377 status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyBufferSize, &propertySize, &ao->chunk_size);
383 if (status) { 378 if (status) {
384 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceGetProperty returned %d when getting kAudioDevicePropertyBufferSize\n", (int)status); 379 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceGetProperty returned %d when getting kAudioDevicePropertyBufferSize\n", (int)status);
385 return CONTROL_FALSE; 380 return CONTROL_FALSE;
386 } 381 }
387 ao_msg(MSGT_AO,MSGL_V, "%5d ao->buffer_len\n", (int)ao->buffer_len); 382 ao_msg(MSGT_AO,MSGL_V, "%5d chunk size\n", (int)ao->chunk_size);
388 383
389 ao_data.samplerate = ao->outputStreamBasicDescription.mSampleRate; 384 ao_data.samplerate = ao->outputStreamBasicDescription.mSampleRate;
390 ao_data.channels = channels; 385 ao_data.channels = channels;
391 ao_data.outburst = ao_data.buffersize = ao->buffer_len; 386 ao_data.outburst = ao_data.buffersize = ao->chunk_size;
392 ao_data.bps = 387 ao_data.bps =
393 ao_data.samplerate * ao->outputStreamBasicDescription.mBytesPerFrame; 388 ao_data.samplerate * ao->outputStreamBasicDescription.mBytesPerFrame;
394 389
395 if (ao->outputStreamBasicDescription.mFormatID == kAudioFormatLinearPCM) { 390 if (ao->outputStreamBasicDescription.mFormatID == kAudioFormatLinearPCM) {
396 uint32_t flags = ao->outputStreamBasicDescription.mFormatFlags; 391 uint32_t flags = ao->outputStreamBasicDescription.mFormatFlags;
408 "support Linear PCM!\n"); 403 "support Linear PCM!\n");
409 return CONTROL_FALSE; 404 return CONTROL_FALSE;
410 } 405 }
411 406
412 /* Allocate ring-buffer memory */ 407 /* Allocate ring-buffer memory */
413 for(i=0;i<NUM_BUFS;i++) 408 ao->num_chunks = NUM_BUFS;
414 ao->buffer[i]=(unsigned char *) malloc(ao->buffer_len); 409 ao->buffer_len = (ao->num_chunks + 1) * ao->chunk_size;
410 ao->buffer = (unsigned char *)malloc(ao->buffer_len);
415 411
416 412
417 /* Prepare for playback */ 413 /* Prepare for playback */
418 414
419 reset();
420
421 /* Set the IO proc that CoreAudio will call when it needs data */ 415 /* Set the IO proc that CoreAudio will call when it needs data */
422 status = AudioDeviceAddIOProc(ao->outputDeviceID, audioDeviceIOProc, NULL); 416 status = AudioDeviceAddIOProc(ao->outputDeviceID, audioDeviceIOProc, NULL);
423 if (status) { 417 if (status) {
424 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceAddIOProc returned %d\n", (int)status); 418 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceAddIOProc returned %d\n", (int)status);
425 return CONTROL_FALSE; 419 return CONTROL_FALSE;
426 } 420 }
427 421
428 /* Start callback */ 422 /* Start callback */
429 status = AudioDeviceStart(ao->outputDeviceID, audioDeviceIOProc); 423 reset();
430 if (status) {
431 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceStart returned %d\n",
432 (int)status);
433 return CONTROL_FALSE;
434 }
435 424
436 return CONTROL_OK; 425 return CONTROL_OK;
437 } 426 }
438 427
439 428
443 } 432 }
444 433
445 /* set variables and buffer to initial state */ 434 /* set variables and buffer to initial state */
446 static void reset() 435 static void reset()
447 { 436 {
448 int i; 437 audio_pause();
449
450 pthread_mutex_lock(&ao->buffer_mutex);
451
452 /* reset ring-buffer state */ 438 /* reset ring-buffer state */
453 ao->buf_read=0;
454 ao->buf_write=0;
455 ao->buf_read_pos=0; 439 ao->buf_read_pos=0;
456 ao->buf_write_pos=0; 440 ao->buf_write_pos=0;
441 audio_resume();
457 442
458 ao->full_buffers=0;
459 ao->buffered_bytes=0;
460
461 /* zero output buffer */
462 for (i = 0; i < NUM_BUFS; i++)
463 memset(ao->buffer[i], 0, ao->buffer_len);
464
465 pthread_mutex_unlock(&ao->buffer_mutex);
466
467 return; 443 return;
468 } 444 }
469 445
470 446
471 /* return available space */ 447 /* return available space */
472 static int get_space() 448 static int get_space()
473 { 449 {
474 return (NUM_BUFS-ao->full_buffers)*ao_data.buffersize - ao->buf_write_pos; 450 return buf_free();
475 } 451 }
476 452
477 453
478 /* return delay until audio is played */ 454 /* return delay until audio is played */
479 static float get_delay() 455 static float get_delay()
480 { 456 {
481 return (float)(ao->buffered_bytes)/(float)ao_data.bps; 457 int buffered = ao->buffer_len - ao->chunk_size - buf_free(); // could be less
458 // inaccurate, should also contain the data buffered e.g. by the OS
459 return (float)(buffered)/(float)ao_data.bps;
482 } 460 }
483 461
484 462
485 /* unload plugin and deregister from coreaudio */ 463 /* unload plugin and deregister from coreaudio */
486 static void uninit(int immed) 464 static void uninit(int immed)
493 status = AudioDeviceRemoveIOProc(ao->outputDeviceID, audioDeviceIOProc); 471 status = AudioDeviceRemoveIOProc(ao->outputDeviceID, audioDeviceIOProc);
494 if (status) 472 if (status)
495 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceRemoveIOProc " 473 ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceRemoveIOProc "
496 "returned %d\n", (int)status); 474 "returned %d\n", (int)status);
497 475
498 for(i=0;i<NUM_BUFS;i++) free(ao->buffer[i]); 476 free(ao->buffer);
499 free(ao); 477 free(ao);
500 } 478 }
501 479
502 480
503 /* stop playing, keep buffers (for pause) */ 481 /* stop playing, keep buffers (for pause) */