Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members
SDLaudioIO.cpp
00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: SDLaudioIO.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 // SDLaudioIO.cpp: Implementing the Class SDLaudioIO. 00045 // 00047 00048 #include "SDLaudioIO.hpp" 00049 00050 #include <stdio.h> 00051 #include <stdlib.h> 00052 #ifndef WINCE 00053 #include <signal.h> 00054 #endif 00055 00056 00057 00058 /**********************************************/ 00059 SDLaudioIO::SDLaudioIO(AudioESInfo *es, ESSynchronizer *ess) : AudioIO(es, ess) { 00060 initialized = false; 00061 requestUnpauseESS = false; 00062 is = NULL; 00063 } 00064 00065 /**********************************************/ 00066 SDLaudioIO::~SDLaudioIO() { 00067 SDL_CloseAudio(); 00068 } 00069 00070 00071 /**********************************************/ 00072 /* packet queue handling */ 00073 void SDLaudioIO::packet_queue_init() { 00074 memset(&(is->audioq), 0, sizeof(PacketQueue)); 00075 #ifndef WINCE 00076 is->audioq.mutex = SDL_CreateMutex(); 00077 is->audioq.cond = SDL_CreateCond(); 00078 #else 00079 is->audioq.mutex = new VMutex(); 00080 is->audioq.mutex->initialize("audioq.mutex"); 00081 00082 is->audioq.cond = new VCondition(); 00083 is->audioq.cond->initialize(); 00084 #endif 00085 } 00086 00087 00088 /**********************************************/ 00089 /* we need to clear also is->audio_pkt, 00090 * because is->audio_pkt.data points to a buffer 00091 * that will be deleted by this function! 00092 */ 00093 void SDLaudioIO::packet_queue_clear() { 00094 APacketList *pkt, *pkt1; 00095 00096 SDL_LockAudio(); 00097 #ifndef WINCE 00098 SDL_LockMutex(is->audioq.mutex); 00099 #else 00100 is->audioq.mutex->lock(); 00101 #endif 00102 for(pkt = is->audioq.first_pkt; pkt != NULL; pkt = pkt1) { 00103 pkt1 = pkt->next; 00104 delete pkt->pkt.data; 00105 delete pkt; 00106 } 00107 is->audioq.first_pkt = NULL; 00108 is->audioq.last_pkt = NULL; 00109 is->audioq.nb_packets = 0; 00110 is->audioq.size = 0; 00111 is->audio_pkt.size = 0; 00112 is->audio_pkt.pts = 0; 00113 is->audio_pkt.data = NULL; 00114 is->audio_pkt_index = 0; 00115 #ifndef WINCE 00116 SDL_UnlockMutex(is->audioq.mutex); 00117 #else 00118 is->audioq.mutex->release(); 00119 #endif 00120 SDL_UnlockAudio(); 00121 } 00122 00123 00124 /**********************************************/ 00125 void SDLaudioIO::packet_queue_end() { 00126 packet_queue_clear(); 00127 #ifndef WINCE 00128 SDL_DestroyMutex(is->audioq.mutex); 00129 SDL_DestroyCond(is->audioq.cond); 00130 #else 00131 is->audioq.mutex->destroy(); 00132 is->audioq.cond->destroy(); 00133 #endif 00134 } 00135 00136 00137 /**********************************************/ 00138 int SDLaudioIO::packet_queue_put(APacket *pkt) { 00139 APacketList *pkt1; 00140 00141 pkt1 = new APacketList; 00142 if (!pkt1) 00143 return -1; 00144 pkt1->pkt = *pkt; 00145 pkt1->next = NULL; 00146 00147 #ifndef WINCE 00148 SDL_LockMutex(is->audioq.mutex); 00149 #else 00150 is->audioq.mutex->lock(); 00151 #endif 00152 00153 if (!is->audioq.last_pkt) 00154 00155 is->audioq.first_pkt = pkt1; 00156 else 00157 is->audioq.last_pkt->next = pkt1; 00158 is->audioq.last_pkt = pkt1; 00159 is->audioq.nb_packets++; 00160 is->audioq.size += pkt1->pkt.size; 00161 #ifndef WINCE 00162 SDL_CondSignal(is->audioq.cond); 00163 #else 00164 is->audioq.cond->signal(); 00165 #endif 00166 00167 #ifndef WINCE 00168 SDL_UnlockMutex(is->audioq.mutex); 00169 #else 00170 is->audioq.mutex->release(); 00171 #endif 00172 return 0; 00173 } 00174 00175 00176 /**********************************************/ 00177 void SDLaudioIO::packet_queue_abort() { 00178 #ifndef WINCE 00179 SDL_LockMutex(is->audioq.mutex); 00180 #else 00181 is->audioq.mutex->lock(); 00182 #endif 00183 00184 is->audioq.abort_request = 1; 00185 00186 #ifndef WINCE 00187 SDL_CondSignal(is->audioq.cond); 00188 #else 00189 is->audioq.cond->signal(); 00190 #endif 00191 00192 #ifndef WINCE 00193 SDL_UnlockMutex(is->audioq.mutex); 00194 #else 00195 is->audioq.mutex->release(); 00196 #endif 00197 } 00198 00199 00200 /**********************************************/ 00201 /* return < 0 if aborted, 0 if no packet and > 0 if packet. 00202 * This is called by sdl_audio_callback(), so we should avoid 00203 * blocking forever, as this could lead to a deadlock with a 00204 * thread calling SDLaudioIO::close() when the DataChannel 00205 * thread is also blocked. 00206 */ 00207 int SDLaudioIO::packet_queue_get(PacketQueue *q, APacket *pkt, int block) { 00208 APacketList *pkt1; 00209 int ret; 00210 00211 #ifndef WINCE 00212 SDL_LockMutex(q->mutex); 00213 #else 00214 q->mutex->lock(); 00215 #endif 00216 00217 for(;;) { 00218 if (q->abort_request) { 00219 ret = -1; 00220 break; 00221 } 00222 00223 pkt1 = q->first_pkt; 00224 if (pkt1) { 00225 q->first_pkt = pkt1->next; 00226 if (!q->first_pkt) 00227 q->last_pkt = NULL; 00228 q->nb_packets--; 00229 q->size -= pkt1->pkt.size; 00230 *pkt = pkt1->pkt; 00231 delete pkt1; 00232 ret = 1; 00233 break; 00234 } else if (!block) { 00235 ret = 0; 00236 break; 00237 } else { 00238 // block at most 100 ms 00239 #ifndef WINCE 00240 ret = SDL_CondWaitTimeout(q->cond, q->mutex, 100); 00241 #else 00242 dprintf_full("SDLaudioIO: packet_queue_get() sleeping\n"); 00243 Sleep(100); 00244 q->cond->condWait(); 00245 ret = 1; 00246 #endif 00247 if (ret == SDL_MUTEX_TIMEDOUT) { 00248 ret = 0; 00249 break; 00250 } else if (ret < 0) // error 00251 break; 00252 // else condition was signalled, continue 00253 } 00254 } 00255 #ifndef WINCE 00256 SDL_UnlockMutex(q->mutex); 00257 #else 00258 q->mutex->release(); 00259 #endif 00260 return ret; 00261 } 00262 00263 00264 const char *SDLaudioIO::get_sdl_audio_state() const { 00265 static char *stat[] = {"unknown", "stopped", "paused", "playing"}; 00266 char *retval = stat[0]; 00267 SDL_audiostatus status = SDL_GetAudioStatus(); 00268 switch(status) { 00269 case SDL_AUDIO_STOPPED: 00270 retval = stat[1]; 00271 break; 00272 case SDL_AUDIO_PAUSED: 00273 retval = stat[2]; 00274 break; 00275 case SDL_AUDIO_PLAYING: 00276 retval = stat[3]; 00277 break; 00278 } 00279 return retval; 00280 } 00281 00282 00283 /**********************************************/ 00284 /* prepare a new audio buffer */ 00285 void sdl_audio_callback(void *opaque, u8 *stream, int length) { 00286 AudioState *is = (AudioState *)opaque; 00287 SDLaudioIO *aud = is->selfClass; 00288 APacket *pkt = &is->audio_pkt; 00289 int len = length; 00290 int len1; 00291 bool pempty = false; // packet queue empty? 00292 00293 while (len > 0) { 00294 // is->audio_pkt fully delivered to SDL? 00295 if (is->audio_pkt_index >= pkt->size) { 00296 /* delete old packet data */ 00297 if (pkt->size > 0 && pkt->data) 00298 delete pkt->data; 00299 pkt->size = 0; 00300 is->audio_pkt_index = 0; 00301 if (aud->packet_queue_get(&is->audioq, pkt, 1) <= 0) { 00302 /* no packet available or error, just output silence */ 00303 dprintf_full("SDLaudioIO: sdl_audio_callback() packet queue empty or error\n"); 00304 memset(stream, 0, len); 00305 pempty = true; 00306 break; // leave pkt->pts untouched 00307 } 00308 } 00309 len1 = pkt->size - is->audio_pkt_index; 00310 if (len1 > len) 00311 len1 = len; 00312 memcpy(stream, pkt->data + is->audio_pkt_index, len1); 00313 len -= len1; 00314 stream += len1; 00315 is->audio_pkt_index += len1; 00316 } 00317 00318 dprintf_full("SDLaudioIO: sdl_audio_callback() copied %d bytes to SDL audio buffer, " 00319 "audio_pkt_index = %d, pkt->size = %d, PTS = %u\n", 00320 length, is->audio_pkt_index, pkt->size, ((u32)pkt->pts)); 00321 00322 00323 dprintf_full("SDLaudioIO: sdl_audio_callback() pemtpy is %d, aud->lastpts=%ld, pkt->pts=%ld", pempty, aud->getLastPTS(), (long int)pkt->pts); 00324 00325 if (!pempty) { 00326 #ifndef WINCE 00327 if ((unsigned)aud->getLastPTS() != pkt->pts) { 00328 #endif 00329 if (aud->getESSync()) 00330 aud->getESSync()->getGlobalTimer()->adjustToTS(pkt->pts, is->ticks_per_second); 00331 /* if first packet, unpause video (after adjusting the GlobalTimer!) */ 00332 if (aud->requestUnpauseESS && aud->getESSync()) { 00333 dprintf_full("SDLaudioIO: sdl_audio_callback() unpausing ESSychronizer\n"); 00334 aud->requestUnpauseESS = false; 00335 aud->getESSync()->setPaused(false); 00336 } 00337 aud->setLastPTS(pkt->pts); 00338 #ifndef WINCE 00339 } 00340 #endif 00341 } 00342 00343 } 00344 00345 00346 /**********************************************/ 00347 int SDLaudioIO::initialize() 00348 { 00349 if (initialized) 00350 return 0; 00351 dprintf_full("SDLaudioIO::initialize() Using SDL audio library\n"); 00352 00353 if(es) { 00354 int flags; 00355 00356 flags = SDL_INIT_AUDIO | SDL_INIT_TIMER; 00357 00358 //#ifndef WIN32 00359 flags |= SDL_INIT_EVENTTHREAD; /* Not supported on win32 */ 00360 //#endif 00361 00362 if (SDL_Init (flags)) { 00363 dprintf_err("Could not initialize SDL - exiting\n"); 00364 ::exit(1); 00365 } 00366 00367 is = new AudioState; 00368 if (!is){ 00369 dprintf_err("Error in Allocating AudioState\n"); 00370 return -1; 00371 } 00372 is->selfClass = this; //get obj-ptr for static SDL functions 00373 is->abort_request = 0; 00374 is->audio_pkt_index = 0; 00375 is->audio_pkt_time_increment = 0; 00376 is->ticks_per_second = es->getMediaTimeScale(); 00377 if (!is->ticks_per_second) 00378 is->ticks_per_second = 90000; 00379 is->queue_full_delay = 0; 00380 memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); 00381 packet_queue_init(); 00382 00383 SDL_AudioSpec wanted_spec; 00384 00385 /* prepare audio output */ 00386 wanted_spec.freq = es->getSampleRate(); 00387 00388 wanted_spec.format = AUDIO_S16SYS; 00389 wanted_spec.channels = es->getAudioChannels(); 00390 wanted_spec.silence = 0; 00391 wanted_spec.samples = SDL_AUDIO_BUFFER_SAMPLES; 00392 wanted_spec.callback = sdl_audio_callback; 00393 wanted_spec.userdata = is; 00394 if (SDL_OpenAudio(&wanted_spec, &is->spec) < 0) { 00395 dprintf_err("SDLaudioIO::initialize() SDL_OpenAudio: %s\n", 00396 SDL_GetError()); 00397 return -1; 00398 } 00399 00400 SDL_PauseAudio(0); 00401 00402 dprintf_full("SDLaudioIO::initialize() Freq = %d (wanted %d) Channels = %u " 00403 "Samples = %u Buffer Size = %u Format = %u\r\n", 00404 is->spec.freq, wanted_spec.freq, is->spec.channels, is->spec.samples, 00405 is->spec.size, is->spec.format); 00406 } 00407 else { 00408 dprintf_err("SDLaudioIO::initialize() failed no ES\r\n"); 00409 return -1; 00410 } 00411 initialized = true; 00412 return 0; 00413 } 00414 00415 int SDLaudioIO::restartSDLThread() 00416 { 00417 if (!initialized) { 00418 initialize(); 00419 } else { 00420 SDL_AudioSpec wanted_spec = is->spec; 00421 SDL_CloseAudio(); 00422 if (SDL_OpenAudio(&wanted_spec, &is->spec) < 0) { 00423 dprintf_err("SDLaudioIO::restartSDLThread() SDL_OpenAudio: %s\n", 00424 SDL_GetError()); 00425 return -1; 00426 } 00427 dprintf_full("SDLaudioIO::restartSDLThread() Freq = %d Channels = %u " 00428 "Samples = %u Buffer Size = %u Format = %u\r\n", 00429 is->spec.freq, is->spec.channels, is->spec.samples, 00430 is->spec.size, is->spec.format); 00431 SDL_PauseAudio(0); 00432 } 00433 return 0; 00434 } 00435 00436 /**********************************************/ 00437 Frame * SDLaudioIO::getFrame() { 00438 dprintf_full("SDLaudioIO::getFrame NOT IMPLEMENTED!\n"); 00439 00440 #ifdef _POSIX_PRIORITY_SCHEDULING 00441 sched_yield(); //this is necessary to give parallel getFrames a chance 00442 #endif 00443 00444 return NULL; 00445 } 00446 00447 00448 00449 /**********************************************/ 00450 int SDLaudioIO::writeFrame(Frame * frm, ESInfo *out_es) { 00451 int ntrials = 20; // number of delay calls when queue is full 00452 int i; 00453 00454 if (!initialized) { 00455 if(initialize() < 0) { 00456 dprintf_err("SDLaudioIO::writeFrame() Error in initializing\n"); 00457 return 0; 00458 } 00459 } 00460 if (!frm->getAU()->size) { 00461 return 0; 00462 } 00463 if(firstFrame) { 00464 firstFrame = false; 00465 } 00466 num_frames++; 00467 00468 if (!is->audio_pkt_time_increment) { 00469 u32 bits_per_second = es->getSampleRate() * es->getBitsPerSample() * es->getAudioChannels(); 00470 if (bits_per_second) { 00471 is->audio_pkt_time_increment = frm->getAU()->size * 1000 * 8 / bits_per_second; 00472 dprintf_full("SDLaudioIO::writeFrame(): is->audio_pkt_time_increment = %d, AUsize = %d, bps = %d", is->audio_pkt_time_increment, frm->getAU()->size, bits_per_second); 00473 } 00474 else 00475 is->audio_pkt_time_increment = 1000; 00476 /* compute blocking delay (in ms) when queue is full; 00477 * (ntrials * delay) >= audio_pkt_time_increment 00478 * is minimally required to avoid loosing packets. 00479 */ 00480 //is->queue_full_delay = is->audio_pkt_time_increment * 2 / ntrials; 00481 is->queue_full_delay = is->audio_pkt_time_increment * 2; 00482 if (is->audio_pkt_time_increment > 50 || is->audio_pkt_time_increment <= 0) is->audio_pkt_time_increment = 50; //100 msecs 00483 00484 dprintf_full("SDLaudioIO::writeFrame() pkt_time_increment = %u ms, " 00485 "queue_full_delay = %u ms\n", 00486 is->audio_pkt_time_increment, is->queue_full_delay); 00487 } 00488 00489 if(IO::getState() != IO::MUTED) { 00490 assert(frm->getAU()->payload != NULL); 00491 /* work around a problem on Linux where the SDL audio thread happens to die 00492 * unexpectedly 00493 */ 00494 if (SDL_GetAudioStatus() == SDL_AUDIO_STOPPED) { 00495 dprintf_small("SDLaudioIO::writeFrame() detected dead SDL thread - re-starting\n"); 00496 restartSDLThread(); 00497 } 00498 00499 /* if the queue is full, block for a finite period of time */ 00500 for (i = ntrials; is->audioq.size > SDL_MAX_AUDIOQ_SIZE && i > 0; i--) { 00501 dprintf_full("SDLaudioIO::writeFrame() Queue Full! aqsize=%d max=%d i=%d\n", is->audioq.size, SDL_MAX_AUDIOQ_SIZE, i); 00502 SDL_Delay(is->queue_full_delay); 00503 } 00504 00505 if (is->audioq.size > SDL_MAX_AUDIOQ_SIZE) { 00506 dprintf_small("SDLaudioIO::writeFrame() Queue full - dropping packet!\n" 00507 " SDL audio state = %s\n", 00508 get_sdl_audio_state()); 00509 return 0; 00510 } 00511 00512 /* enqueue new packet */ 00513 APacket pkt1, *pkt = &pkt1; 00514 pkt->size = frm->getAU()->size; //size 00515 pkt->pts = frm->getAU()->cts; //presentation timestamp 00516 pkt->data = new u8[pkt->size]; 00517 00518 memcpy(pkt->data, frm->getAU()->payload, pkt->size); 00519 00520 dprintf_full("SDLaudioIO::writeFrame() PTS %u SIZE %i audioq size = %i\n", 00521 ((u32)pkt->pts), pkt->size, is->audioq.size); 00522 00523 if(packet_queue_put(pkt) < 0) { 00524 dprintf_err("SDLaudioIO::writeFrame() Error in putting packet into Queue\n"); 00525 delete pkt->data; 00526 return 0; 00527 } 00528 } 00529 00530 #ifdef _POSIX_PRIORITY_SCHEDULING 00531 sched_yield(); //this is necessary to give parallel getFrames a chance 00532 #endif 00533 00534 return 1; 00535 } 00536 00537 00538 /**********************************************/ 00539 /* we should NOT initialize() here as ESInfo data 00540 * may not be available yet 00541 */ 00542 bool SDLaudioIO::open() { 00543 if (essync) { 00544 dprintf_full("SDLaudioIO::open() SDL audio state = %s, PAUSING ESSynchronizer\n", 00545 get_sdl_audio_state()); 00546 essync->setPaused(true); 00547 requestUnpauseESS = true; // no locking, as the SDL thread is not running yet 00548 } 00549 initialized = false; 00550 setState(OPEN); 00551 return true; 00552 } 00553 00554 00555 /**********************************************/ 00556 int SDLaudioIO::getPacketsInQueue() 00557 { 00558 int packetsInQueue = 0; 00559 00560 #ifndef WINCE 00561 SDL_LockMutex(is->audioq.mutex); 00562 #else 00563 is->audioq.mutex->lock(); 00564 #endif 00565 00566 00567 packetsInQueue = is->audioq.nb_packets; 00568 00569 00570 #ifndef WINCE 00571 SDL_CondSignal(is->audioq.cond); 00572 #else 00573 is->audioq.cond->signal(); 00574 #endif 00575 00576 #ifndef WINCE 00577 SDL_UnlockMutex(is->audioq.mutex); 00578 #else 00579 is->audioq.mutex->release(); 00580 #endif 00581 00582 dprintf_full("SDLaudioIO::close() packets in queue: %d\n", packetsInQueue); 00583 return packetsInQueue; 00584 } 00585 00586 /**********************************************/ 00587 bool SDLaudioIO::close(bool immediate) { 00588 00589 if (!immediate) { 00590 while (this->getPacketsInQueue() > 0) msleep(500); 00591 } 00592 00593 if(initialized) { 00594 packet_queue_abort(/*&is->audioq*/); 00595 SDL_CloseAudio(); 00596 packet_queue_end(/*&is->audioq*/); 00597 if(is) 00598 delete is; 00599 } 00600 setState(CLOSED); 00601 dprintf_full("SDLaudioIO::close() SDL audio state after SDL_CloseAudio() = %s\n", 00602 get_sdl_audio_state()); 00603 initialized = false; 00604 return true; 00605 } 00606 00607 00608 /**********************************************/ 00609 IO::State SDLaudioIO::pause() { 00610 /* pause audio callback processing, will also protect requestUnpauseESS */ 00611 SDL_PauseAudio(1); 00612 dprintf_full("SDLaudioIO::pause() SDL audio state after SDL_PauseAudio(1) = %s\n", 00613 get_sdl_audio_state()); 00614 return setState(PAUSED); 00615 } 00616 00617 00618 /**********************************************/ 00619 IO::State SDLaudioIO::play(double prefetchTime) { 00620 if(IO::getState() == MUTED) 00621 return setState(OPEN); 00622 00623 if (essync) { 00624 essync->setPaused(true); // for A/V sync, unpaused by sdl_audio_callback() 00625 requestUnpauseESS = true; 00626 } 00627 if (initialized) { 00628 SDL_PauseAudio(0); 00629 dprintf_full("SDLaudioIO::play() SDL audio state after SDL_PauseAudio(0) = %s\n", 00630 get_sdl_audio_state()); 00631 /* work around a problem on Linux, where SDL_PauseAudio(0) 00632 * leaves SDL audio status at STOPPED (meaning the SDL audio thread 00633 * has already terminated). 00634 */ 00635 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING) { 00636 dprintf_full("SDLaudioIO::play() detected dead SDL audio thread - re-starting\n"); 00637 restartSDLThread(); 00638 } 00639 } 00640 return setState(OPEN); 00641 } 00642 00643 00644 IO::State SDLaudioIO::mute() { 00645 return setState(MUTED); 00646 } 00647 00648 00649 void SDLaudioIO::clearBuffer() { 00650 packet_queue_clear(); 00651 } 00652