119 if(err == -EPIPE) { |
119 if(err == -EPIPE) { |
120 errorState = QAudio::UnderrunError; |
120 errorState = QAudio::UnderrunError; |
121 err = snd_pcm_prepare(handle); |
121 err = snd_pcm_prepare(handle); |
122 if(err < 0) |
122 if(err < 0) |
123 reset = true; |
123 reset = true; |
|
124 else { |
|
125 bytesAvailable = bytesReady(); |
|
126 if (bytesAvailable <= 0) |
|
127 reset = true; |
|
128 } |
124 |
129 |
125 } else if((err == -ESTRPIPE)||(err == -EIO)) { |
130 } else if((err == -ESTRPIPE)||(err == -EIO)) { |
126 errorState = QAudio::IOError; |
131 errorState = QAudio::IOError; |
127 while((err = snd_pcm_resume(handle)) == -EAGAIN){ |
132 while((err = snd_pcm_resume(handle)) == -EAGAIN){ |
128 usleep(100); |
133 usleep(100); |
437 int QAudioInputPrivate::bytesReady() const |
443 int QAudioInputPrivate::bytesReady() const |
438 { |
444 { |
439 if(resuming) |
445 if(resuming) |
440 return period_size; |
446 return period_size; |
441 |
447 |
442 if(deviceState != QAudio::ActiveState) |
448 if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) |
443 return 0; |
449 return 0; |
444 int frames = snd_pcm_avail_update(handle); |
450 int frames = snd_pcm_avail_update(handle); |
|
451 if (frames < 0) return frames; |
445 if((int)frames > (int)buffer_frames) |
452 if((int)frames > (int)buffer_frames) |
446 frames = buffer_frames; |
453 frames = buffer_frames; |
447 |
454 |
448 return snd_pcm_frames_to_bytes(handle, frames); |
455 return snd_pcm_frames_to_bytes(handle, frames); |
449 } |
456 } |
450 |
457 |
451 qint64 QAudioInputPrivate::read(char* data, qint64 len) |
458 qint64 QAudioInputPrivate::read(char* data, qint64 len) |
452 { |
459 { |
453 Q_UNUSED(data) |
|
454 Q_UNUSED(len) |
460 Q_UNUSED(len) |
|
461 |
455 // Read in some audio data and write it to QIODevice, pull mode |
462 // Read in some audio data and write it to QIODevice, pull mode |
456 if ( !handle ) |
463 if ( !handle ) |
457 return 0; |
464 return 0; |
458 |
465 |
459 bytesAvailable = bytesReady(); |
466 bytesAvailable = bytesReady(); |
|
467 |
|
468 if (bytesAvailable < 0) { |
|
469 // bytesAvailable as negative is error code, try to recover from it. |
|
470 xrun_recovery(bytesAvailable); |
|
471 bytesAvailable = bytesReady(); |
|
472 if (bytesAvailable < 0) { |
|
473 // recovery failed must stop and set error. |
|
474 close(); |
|
475 errorState = QAudio::IOError; |
|
476 deviceState = QAudio::StoppedState; |
|
477 emit stateChanged(deviceState); |
|
478 return 0; |
|
479 } |
|
480 } |
460 |
481 |
461 int count=0, err = 0; |
482 int count=0, err = 0; |
462 while(count < 5) { |
483 while(count < 5) { |
463 int chunks = bytesAvailable/period_size; |
484 int chunks = bytesAvailable/period_size; |
464 int frames = chunks*period_frames; |
485 int frames = chunks*period_frames; |
466 frames = buffer_frames; |
487 frames = buffer_frames; |
467 int readFrames = snd_pcm_readi(handle, audioBuffer, frames); |
488 int readFrames = snd_pcm_readi(handle, audioBuffer, frames); |
468 if (readFrames >= 0) { |
489 if (readFrames >= 0) { |
469 err = snd_pcm_frames_to_bytes(handle, readFrames); |
490 err = snd_pcm_frames_to_bytes(handle, readFrames); |
470 #ifdef DEBUG_AUDIO |
491 #ifdef DEBUG_AUDIO |
471 qDebug()<<QString::fromLatin1("PULL: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData(); |
492 qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData(); |
472 #endif |
493 #endif |
473 break; |
494 break; |
474 } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { |
495 } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { |
475 errorState = QAudio::IOError; |
496 errorState = QAudio::IOError; |
476 err = 0; |
497 err = 0; |
487 count++; |
508 count++; |
488 } |
509 } |
489 if(err > 0) { |
510 if(err > 0) { |
490 // got some send it onward |
511 // got some send it onward |
491 #ifdef DEBUG_AUDIO |
512 #ifdef DEBUG_AUDIO |
492 qDebug()<<"PULL: frames to write to QIODevice = "<< |
513 qDebug()<<"frames to write to QIODevice = "<< |
493 snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes"; |
514 snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes"; |
494 #endif |
515 #endif |
495 if(deviceState != QAudio::ActiveState) |
516 if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) |
496 return 0; |
517 return 0; |
497 |
518 if (pullMode) { |
498 qint64 l = audioSource->write(audioBuffer,err); |
519 qint64 l = audioSource->write(audioBuffer,err); |
499 if(l < 0) { |
520 if(l < 0) { |
500 close(); |
521 close(); |
501 errorState = QAudio::IOError; |
522 errorState = QAudio::IOError; |
502 deviceState = QAudio::StoppedState; |
523 deviceState = QAudio::StoppedState; |
503 emit stateChanged(deviceState); |
524 emit stateChanged(deviceState); |
504 } else if(l == 0) { |
525 } else if(l == 0) { |
505 errorState = QAudio::NoError; |
526 if (deviceState != QAudio::IdleState) { |
506 deviceState = QAudio::IdleState; |
527 errorState = QAudio::NoError; |
|
528 deviceState = QAudio::IdleState; |
|
529 emit stateChanged(deviceState); |
|
530 } |
|
531 } else { |
|
532 totalTimeValue += err; |
|
533 resuming = false; |
|
534 if (deviceState != QAudio::ActiveState) { |
|
535 errorState = QAudio::NoError; |
|
536 deviceState = QAudio::ActiveState; |
|
537 emit stateChanged(deviceState); |
|
538 } |
|
539 } |
|
540 return l; |
|
541 |
507 } else { |
542 } else { |
508 totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency(); |
543 memcpy(data,audioBuffer,err); |
|
544 totalTimeValue += err; |
509 resuming = false; |
545 resuming = false; |
510 errorState = QAudio::NoError; |
546 if (deviceState != QAudio::ActiveState) { |
511 deviceState = QAudio::ActiveState; |
547 errorState = QAudio::NoError; |
512 } |
548 deviceState = QAudio::ActiveState; |
513 return l; |
549 emit stateChanged(deviceState); |
|
550 } |
|
551 return err; |
|
552 } |
514 } |
553 } |
515 return 0; |
554 return 0; |
516 } |
555 } |
517 |
556 |
518 void QAudioInputPrivate::resume() |
557 void QAudioInputPrivate::resume() |
567 return intervalTime; |
606 return intervalTime; |
568 } |
607 } |
569 |
608 |
570 qint64 QAudioInputPrivate::processedUSecs() const |
609 qint64 QAudioInputPrivate::processedUSecs() const |
571 { |
610 { |
572 return totalTimeValue; |
611 qint64 result = qint64(1000000) * totalTimeValue / |
|
612 (settings.channels()*(settings.sampleSize()/8)) / |
|
613 settings.frequency(); |
|
614 |
|
615 return result; |
573 } |
616 } |
574 |
617 |
575 void QAudioInputPrivate::suspend() |
618 void QAudioInputPrivate::suspend() |
576 { |
619 { |
577 if(deviceState == QAudio::ActiveState||resuming) { |
620 if(deviceState == QAudio::ActiveState||resuming) { |
615 return true; |
658 return true; |
616 } |
659 } |
617 |
660 |
618 qint64 QAudioInputPrivate::elapsedUSecs() const |
661 qint64 QAudioInputPrivate::elapsedUSecs() const |
619 { |
662 { |
620 if(!handle) |
|
621 return 0; |
|
622 |
|
623 if (deviceState == QAudio::StoppedState) |
663 if (deviceState == QAudio::StoppedState) |
624 return 0; |
664 return 0; |
625 |
665 |
626 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) |
|
627 snd_pcm_status_t* status; |
|
628 snd_pcm_status_alloca(&status); |
|
629 |
|
630 snd_timestamp_t t1,t2; |
|
631 if( snd_pcm_status(handle, status) >= 0) { |
|
632 snd_pcm_status_get_tstamp(status,&t1); |
|
633 snd_pcm_status_get_trigger_tstamp(status,&t2); |
|
634 t1.tv_sec-=t2.tv_sec; |
|
635 |
|
636 signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec; |
|
637 if(l < 0) { |
|
638 t1.tv_sec--; |
|
639 l = -l; |
|
640 l %= 1000000; |
|
641 } |
|
642 return ((t1.tv_sec * 1000000)+l); |
|
643 } else |
|
644 return 0; |
|
645 #else |
|
646 return clockStamp.elapsed()*1000; |
666 return clockStamp.elapsed()*1000; |
647 #endif |
|
648 } |
667 } |
649 |
668 |
650 void QAudioInputPrivate::reset() |
669 void QAudioInputPrivate::reset() |
651 { |
670 { |
652 if(handle) |
671 if(handle) |
668 { |
687 { |
669 } |
688 } |
670 |
689 |
671 qint64 InputPrivate::readData( char* data, qint64 len) |
690 qint64 InputPrivate::readData( char* data, qint64 len) |
672 { |
691 { |
673 // push mode, user read() called |
692 return audioDevice->read(data,len); |
674 if((audioDevice->state() != QAudio::ActiveState) && !audioDevice->resuming) |
|
675 return 0; |
|
676 |
|
677 int readFrames; |
|
678 int count=0, err = 0; |
|
679 |
|
680 while(count < 5) { |
|
681 int frames = snd_pcm_bytes_to_frames(audioDevice->handle, len); |
|
682 readFrames = snd_pcm_readi(audioDevice->handle, data, frames); |
|
683 if (readFrames >= 0) { |
|
684 err = snd_pcm_frames_to_bytes(audioDevice->handle, readFrames); |
|
685 #ifdef DEBUG_AUDIO |
|
686 qDebug()<<QString::fromLatin1("PUSH: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData(); |
|
687 #endif |
|
688 break; |
|
689 } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { |
|
690 audioDevice->errorState = QAudio::IOError; |
|
691 err = 0; |
|
692 break; |
|
693 } else { |
|
694 if(readFrames == -EPIPE) { |
|
695 audioDevice->errorState = QAudio::UnderrunError; |
|
696 err = snd_pcm_prepare(audioDevice->handle); |
|
697 } else if(readFrames == -ESTRPIPE) { |
|
698 err = snd_pcm_prepare(audioDevice->handle); |
|
699 } |
|
700 if(err != 0) break; |
|
701 } |
|
702 count++; |
|
703 } |
|
704 if(err > 0 && readFrames > 0) { |
|
705 audioDevice->totalTimeValue += readFrames*1000/audioDevice->settings.frequency()*1000; |
|
706 audioDevice->deviceState = QAudio::ActiveState; |
|
707 return err; |
|
708 } |
|
709 return 0; |
|
710 } |
693 } |
711 |
694 |
712 qint64 InputPrivate::writeData(const char* data, qint64 len) |
695 qint64 InputPrivate::writeData(const char* data, qint64 len) |
713 { |
696 { |
714 Q_UNUSED(data) |
697 Q_UNUSED(data) |