Mercurial > mplayer.hg
comparison libao2/ao_macosx.c @ 29201:06e7728c5b34
Use libavutil/fifo.h for macosx ao instead of its own FIFO implementation.
author | reimar |
---|---|
date | Sun, 03 May 2009 20:57:37 +0000 |
parents | 9a5b8c2ed6de |
children |
comparison
equal
deleted
inserted
replaced
29200:80492f643e9b | 29201:06e7728c5b34 |
---|---|
50 | 50 |
51 #include "audio_out.h" | 51 #include "audio_out.h" |
52 #include "audio_out_internal.h" | 52 #include "audio_out_internal.h" |
53 #include "libaf/af_format.h" | 53 #include "libaf/af_format.h" |
54 #include "osdep/timer.h" | 54 #include "osdep/timer.h" |
55 #include "libavutil/fifo.h" | |
55 | 56 |
56 static const ao_info_t info = | 57 static const ao_info_t info = |
57 { | 58 { |
58 "Darwin/Mac OS X native audio output", | 59 "Darwin/Mac OS X native audio output", |
59 "macosx", | 60 "macosx", |
89 /* Original common part */ | 90 /* Original common part */ |
90 int packetSize; | 91 int packetSize; |
91 int paused; | 92 int paused; |
92 | 93 |
93 /* Ring-buffer */ | 94 /* Ring-buffer */ |
94 /* does not need explicit synchronization, but needs to allocate | 95 AVFifoBuffer *buffer; |
95 * (num_chunks + 1) * chunk_size memory to store num_chunks * chunk_size | 96 unsigned int buffer_len; ///< must always be num_chunks * chunk_size |
96 * data */ | |
97 unsigned char *buffer; | |
98 unsigned int buffer_len; ///< must always be (num_chunks + 1) * chunk_size | |
99 unsigned int num_chunks; | 97 unsigned int num_chunks; |
100 unsigned int chunk_size; | 98 unsigned int chunk_size; |
101 | |
102 unsigned int buf_read_pos; | |
103 unsigned int buf_write_pos; | |
104 } ao_macosx_t; | 99 } ao_macosx_t; |
105 | 100 |
106 static ao_macosx_t *ao = NULL; | 101 static ao_macosx_t *ao = NULL; |
107 | |
108 /** | |
109 * \brief return number of free bytes in the buffer | |
110 * may only be called by mplayer's thread | |
111 * \return minimum number of free bytes in buffer, value may change between | |
112 * two immediately following calls, and the real number of free bytes | |
113 * might actually be larger! | |
114 */ | |
115 static int buf_free(void) { | |
116 int free = ao->buf_read_pos - ao->buf_write_pos - ao->chunk_size; | |
117 if (free < 0) free += ao->buffer_len; | |
118 return free; | |
119 } | |
120 | |
121 /** | |
122 * \brief return number of buffered bytes | |
123 * may only be called by playback thread | |
124 * \return minimum number of buffered bytes, value may change between | |
125 * two immediately following calls, and the real number of buffered bytes | |
126 * might actually be larger! | |
127 */ | |
128 static int buf_used(void) { | |
129 int used = ao->buf_write_pos - ao->buf_read_pos; | |
130 if (used < 0) used += ao->buffer_len; | |
131 return used; | |
132 } | |
133 | 102 |
134 /** | 103 /** |
135 * \brief add data to ringbuffer | 104 * \brief add data to ringbuffer |
136 */ | 105 */ |
137 static int write_buffer(unsigned char* data, int len){ | 106 static int write_buffer(unsigned char* data, int len){ |
138 int first_len = ao->buffer_len - ao->buf_write_pos; | 107 int free = ao->buffer_len - av_fifo_size(ao->buffer); |
139 int free = buf_free(); | |
140 if (len > free) len = free; | 108 if (len > free) len = free; |
141 if (first_len > len) first_len = len; | 109 return av_fifo_generic_write(ao->buffer, data, len, NULL); |
142 // till end of buffer | |
143 memcpy (&ao->buffer[ao->buf_write_pos], data, first_len); | |
144 if (len > first_len) { // we have to wrap around | |
145 // remaining part from beginning of buffer | |
146 memcpy (ao->buffer, &data[first_len], len - first_len); | |
147 } | |
148 ao->buf_write_pos = (ao->buf_write_pos + len) % ao->buffer_len; | |
149 return len; | |
150 } | 110 } |
151 | 111 |
152 /** | 112 /** |
153 * \brief remove data from ringbuffer | 113 * \brief remove data from ringbuffer |
154 */ | 114 */ |
155 static int read_buffer(unsigned char* data,int len){ | 115 static int read_buffer(unsigned char* data,int len){ |
156 int first_len = ao->buffer_len - ao->buf_read_pos; | 116 int buffered = av_fifo_size(ao->buffer); |
157 int buffered = buf_used(); | |
158 if (len > buffered) len = buffered; | 117 if (len > buffered) len = buffered; |
159 if (first_len > len) first_len = len; | 118 return av_fifo_generic_read(ao->buffer, data, len, NULL); |
160 // till end of buffer | |
161 if (data) { | |
162 memcpy (data, &ao->buffer[ao->buf_read_pos], first_len); | |
163 if (len > first_len) { // we have to wrap around | |
164 // remaining part from beginning of buffer | |
165 memcpy (&data[first_len], ao->buffer, len - first_len); | |
166 } | |
167 } | |
168 ao->buf_read_pos = (ao->buf_read_pos + len) % ao->buffer_len; | |
169 return len; | |
170 } | 119 } |
171 | 120 |
172 OSStatus theRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData) | 121 OSStatus theRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData) |
173 { | 122 { |
174 int amt=buf_used(); | 123 int amt=av_fifo_size(ao->buffer); |
175 int req=(inNumFrames)*ao->packetSize; | 124 int req=(inNumFrames)*ao->packetSize; |
176 | 125 |
177 if(amt>req) | 126 if(amt>req) |
178 amt=req; | 127 amt=req; |
179 | 128 |
491 ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame; | 440 ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame; |
492 ao_data.outburst = ao->chunk_size; | 441 ao_data.outburst = ao->chunk_size; |
493 ao_data.buffersize = ao_data.bps; | 442 ao_data.buffersize = ao_data.bps; |
494 | 443 |
495 ao->num_chunks = (ao_data.bps+ao->chunk_size-1)/ao->chunk_size; | 444 ao->num_chunks = (ao_data.bps+ao->chunk_size-1)/ao->chunk_size; |
496 ao->buffer_len = (ao->num_chunks + 1) * ao->chunk_size; | 445 ao->buffer_len = ao->num_chunks * ao->chunk_size; |
497 ao->buffer = calloc(ao->num_chunks + 1, ao->chunk_size); | 446 ao->buffer = av_fifo_alloc(ao->buffer_len); |
498 | 447 |
499 ao_msg(MSGT_AO,MSGL_V, "using %5d chunks of %d bytes (buffer len %d bytes)\n", (int)ao->num_chunks, (int)ao->chunk_size, (int)ao->buffer_len); | 448 ao_msg(MSGT_AO,MSGL_V, "using %5d chunks of %d bytes (buffer len %d bytes)\n", (int)ao->num_chunks, (int)ao->chunk_size, (int)ao->buffer_len); |
500 | 449 |
501 renderCallback.inputProc = theRenderProc; | 450 renderCallback.inputProc = theRenderProc; |
502 renderCallback.inputProcRefCon = 0; | 451 renderCallback.inputProcRefCon = 0; |
513 err_out2: | 462 err_out2: |
514 AudioUnitUninitialize(ao->theOutputUnit); | 463 AudioUnitUninitialize(ao->theOutputUnit); |
515 err_out1: | 464 err_out1: |
516 CloseComponent(ao->theOutputUnit); | 465 CloseComponent(ao->theOutputUnit); |
517 err_out: | 466 err_out: |
518 free(ao->buffer); | 467 av_fifo_free(ao->buffer); |
519 free(ao); | 468 free(ao); |
520 ao = NULL; | 469 ao = NULL; |
521 return CONTROL_FALSE; | 470 return CONTROL_FALSE; |
522 } | 471 } |
523 | 472 |
735 ao_data.bps = ao_data.samplerate * (ao->stream_format.mBytesPerPacket/ao->stream_format.mFramesPerPacket); | 684 ao_data.bps = ao_data.samplerate * (ao->stream_format.mBytesPerPacket/ao->stream_format.mFramesPerPacket); |
736 ao_data.outburst = ao->chunk_size; | 685 ao_data.outburst = ao->chunk_size; |
737 ao_data.buffersize = ao_data.bps; | 686 ao_data.buffersize = ao_data.bps; |
738 | 687 |
739 ao->num_chunks = (ao_data.bps+ao->chunk_size-1)/ao->chunk_size; | 688 ao->num_chunks = (ao_data.bps+ao->chunk_size-1)/ao->chunk_size; |
740 ao->buffer_len = (ao->num_chunks + 1) * ao->chunk_size; | 689 ao->buffer_len = ao->num_chunks * ao->chunk_size; |
741 ao->buffer = calloc(ao->num_chunks + 1, ao->chunk_size); | 690 ao->buffer = av_fifo_alloc(ao->buffer_len); |
742 | 691 |
743 ao_msg(MSGT_AO,MSGL_V, "using %5d chunks of %d bytes (buffer len %d bytes)\n", (int)ao->num_chunks, (int)ao->chunk_size, (int)ao->buffer_len); | 692 ao_msg(MSGT_AO,MSGL_V, "using %5d chunks of %d bytes (buffer len %d bytes)\n", (int)ao->num_chunks, (int)ao->chunk_size, (int)ao->buffer_len); |
744 | 693 |
745 | 694 |
746 /* Add IOProc callback. */ | 695 /* Add IOProc callback. */ |
780 i_param_size, &ao->i_hog_pid); | 729 i_param_size, &ao->i_hog_pid); |
781 if (err != noErr) | 730 if (err != noErr) |
782 ao_msg(MSGT_AO, MSGL_WARN, "Could not release hogmode: [%4.4s]\n", | 731 ao_msg(MSGT_AO, MSGL_WARN, "Could not release hogmode: [%4.4s]\n", |
783 (char *)&err); | 732 (char *)&err); |
784 } | 733 } |
785 free(ao->buffer); | 734 av_fifo_free(ao->buffer); |
786 free(ao); | 735 free(ao); |
787 ao = NULL; | 736 ao = NULL; |
788 return CONTROL_FALSE; | 737 return CONTROL_FALSE; |
789 } | 738 } |
790 | 739 |
979 const AudioTimeStamp * inInputTime, | 928 const AudioTimeStamp * inInputTime, |
980 AudioBufferList * outOutputData, | 929 AudioBufferList * outOutputData, |
981 const AudioTimeStamp * inOutputTime, | 930 const AudioTimeStamp * inOutputTime, |
982 void * threadGlobals ) | 931 void * threadGlobals ) |
983 { | 932 { |
984 int amt = buf_used(); | 933 int amt = av_fifo_size(ao->buffer); |
985 int req = outOutputData->mBuffers[ao->i_stream_index].mDataByteSize; | 934 int req = outOutputData->mBuffers[ao->i_stream_index].mDataByteSize; |
986 | 935 |
987 if (amt > req) | 936 if (amt > req) |
988 amt = req; | 937 amt = req; |
989 if (amt) | 938 if (amt) |
1028 | 977 |
1029 /* set variables and buffer to initial state */ | 978 /* set variables and buffer to initial state */ |
1030 static void reset(void) | 979 static void reset(void) |
1031 { | 980 { |
1032 audio_pause(); | 981 audio_pause(); |
1033 /* reset ring-buffer state */ | 982 av_fifo_reset(ao->buffer); |
1034 ao->buf_read_pos=0; | |
1035 ao->buf_write_pos=0; | |
1036 | |
1037 return; | |
1038 } | 983 } |
1039 | 984 |
1040 | 985 |
1041 /* return available space */ | 986 /* return available space */ |
1042 static int get_space(void) | 987 static int get_space(void) |
1043 { | 988 { |
1044 return buf_free(); | 989 return ao->buffer_len - av_fifo_size(ao->buffer); |
1045 } | 990 } |
1046 | 991 |
1047 | 992 |
1048 /* return delay until audio is played */ | 993 /* return delay until audio is played */ |
1049 static float get_delay(void) | 994 static float get_delay(void) |
1050 { | 995 { |
1051 int buffered = ao->buffer_len - ao->chunk_size - buf_free(); // could be less | |
1052 // inaccurate, should also contain the data buffered e.g. by the OS | 996 // inaccurate, should also contain the data buffered e.g. by the OS |
1053 return (float)(buffered)/(float)ao_data.bps; | 997 return (float)av_fifo_size(ao->buffer)/(float)ao_data.bps; |
1054 } | 998 } |
1055 | 999 |
1056 | 1000 |
1057 /* unload plugin and deregister from coreaudio */ | 1001 /* unload plugin and deregister from coreaudio */ |
1058 static void uninit(int immed) | 1002 static void uninit(int immed) |
1059 { | 1003 { |
1060 OSStatus err = noErr; | 1004 OSStatus err = noErr; |
1061 UInt32 i_param_size = 0; | 1005 UInt32 i_param_size = 0; |
1062 | 1006 |
1063 if (!immed) { | 1007 if (!immed) { |
1064 long long timeleft=(1000000LL*buf_used())/ao_data.bps; | 1008 long long timeleft=(1000000LL*av_fifo_size(ao->buffer))/ao_data.bps; |
1065 ao_msg(MSGT_AO,MSGL_DBG2, "%d bytes left @%d bps (%d usec)\n", buf_used(), ao_data.bps, (int)timeleft); | 1009 ao_msg(MSGT_AO,MSGL_DBG2, "%d bytes left @%d bps (%d usec)\n", av_fifo_size(ao->buffer), ao_data.bps, (int)timeleft); |
1066 usec_sleep((int)timeleft); | 1010 usec_sleep((int)timeleft); |
1067 } | 1011 } |
1068 | 1012 |
1069 if (!ao->b_digital) { | 1013 if (!ao->b_digital) { |
1070 AudioOutputUnitStop(ao->theOutputUnit); | 1014 AudioOutputUnitStop(ao->theOutputUnit); |
1113 kAudioDevicePropertyHogMode, i_param_size, &ao->i_hog_pid); | 1057 kAudioDevicePropertyHogMode, i_param_size, &ao->i_hog_pid); |
1114 if (err != noErr) ao_msg(MSGT_AO, MSGL_WARN, "Could not release hogmode: [%4.4s]\n", (char *)&err); | 1058 if (err != noErr) ao_msg(MSGT_AO, MSGL_WARN, "Could not release hogmode: [%4.4s]\n", (char *)&err); |
1115 } | 1059 } |
1116 } | 1060 } |
1117 | 1061 |
1118 free(ao->buffer); | 1062 av_fifo_free(ao->buffer); |
1119 free(ao); | 1063 free(ao); |
1120 ao = NULL; | 1064 ao = NULL; |
1121 } | 1065 } |
1122 | 1066 |
1123 | 1067 |