1 /**************************************************************************** |
1 /**************************************************************************** |
2 ** |
2 ** |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
4 ** All rights reserved. |
4 ** All rights reserved. |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
6 ** |
6 ** |
7 ** This file is part of the QtMultimedia module of the Qt Toolkit. |
7 ** This file is part of the QtMultimedia module of the Qt Toolkit. |
8 ** |
8 ** |
437 int QAudioInputPrivate::bytesReady() const |
438 int QAudioInputPrivate::bytesReady() const |
438 { |
439 { |
439 if(resuming) |
440 if(resuming) |
440 return period_size; |
441 return period_size; |
441 |
442 |
442 if(deviceState != QAudio::ActiveState) |
443 if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) |
443 return 0; |
444 return 0; |
444 int frames = snd_pcm_avail_update(handle); |
445 int frames = snd_pcm_avail_update(handle); |
445 if((int)frames > (int)buffer_frames) |
446 if((int)frames > (int)buffer_frames) |
446 frames = buffer_frames; |
447 frames = buffer_frames; |
447 |
448 |
448 return snd_pcm_frames_to_bytes(handle, frames); |
449 return snd_pcm_frames_to_bytes(handle, frames); |
449 } |
450 } |
450 |
451 |
451 qint64 QAudioInputPrivate::read(char* data, qint64 len) |
452 qint64 QAudioInputPrivate::read(char* data, qint64 len) |
452 { |
453 { |
453 Q_UNUSED(data) |
|
454 Q_UNUSED(len) |
454 Q_UNUSED(len) |
|
455 |
455 // Read in some audio data and write it to QIODevice, pull mode |
456 // Read in some audio data and write it to QIODevice, pull mode |
456 if ( !handle ) |
457 if ( !handle ) |
457 return 0; |
458 return 0; |
458 |
459 |
459 bytesAvailable = bytesReady(); |
460 bytesAvailable = bytesReady(); |
466 frames = buffer_frames; |
467 frames = buffer_frames; |
467 int readFrames = snd_pcm_readi(handle, audioBuffer, frames); |
468 int readFrames = snd_pcm_readi(handle, audioBuffer, frames); |
468 if (readFrames >= 0) { |
469 if (readFrames >= 0) { |
469 err = snd_pcm_frames_to_bytes(handle, readFrames); |
470 err = snd_pcm_frames_to_bytes(handle, readFrames); |
470 #ifdef DEBUG_AUDIO |
471 #ifdef DEBUG_AUDIO |
471 qDebug()<<QString::fromLatin1("PULL: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData(); |
472 qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData(); |
472 #endif |
473 #endif |
473 break; |
474 break; |
474 } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { |
475 } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { |
475 errorState = QAudio::IOError; |
476 errorState = QAudio::IOError; |
476 err = 0; |
477 err = 0; |
487 count++; |
488 count++; |
488 } |
489 } |
489 if(err > 0) { |
490 if(err > 0) { |
490 // got some send it onward |
491 // got some send it onward |
491 #ifdef DEBUG_AUDIO |
492 #ifdef DEBUG_AUDIO |
492 qDebug()<<"PULL: frames to write to QIODevice = "<< |
493 qDebug()<<"frames to write to QIODevice = "<< |
493 snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes"; |
494 snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes"; |
494 #endif |
495 #endif |
495 if(deviceState != QAudio::ActiveState) |
496 if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) |
496 return 0; |
497 return 0; |
497 |
498 if (pullMode) { |
498 qint64 l = audioSource->write(audioBuffer,err); |
499 qint64 l = audioSource->write(audioBuffer,err); |
499 if(l < 0) { |
500 if(l < 0) { |
500 close(); |
501 close(); |
501 errorState = QAudio::IOError; |
502 errorState = QAudio::IOError; |
502 deviceState = QAudio::StoppedState; |
503 deviceState = QAudio::StoppedState; |
503 emit stateChanged(deviceState); |
504 emit stateChanged(deviceState); |
504 } else if(l == 0) { |
505 } else if(l == 0) { |
505 errorState = QAudio::NoError; |
506 if (deviceState != QAudio::IdleState) { |
506 deviceState = QAudio::IdleState; |
507 errorState = QAudio::NoError; |
|
508 deviceState = QAudio::IdleState; |
|
509 emit stateChanged(deviceState); |
|
510 } |
|
511 } else { |
|
512 totalTimeValue += err; |
|
513 resuming = false; |
|
514 if (deviceState != QAudio::ActiveState) { |
|
515 errorState = QAudio::NoError; |
|
516 deviceState = QAudio::ActiveState; |
|
517 emit stateChanged(deviceState); |
|
518 } |
|
519 } |
|
520 return l; |
|
521 |
507 } else { |
522 } else { |
508 totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency(); |
523 memcpy(data,audioBuffer,err); |
|
524 totalTimeValue += err; |
509 resuming = false; |
525 resuming = false; |
510 errorState = QAudio::NoError; |
526 if (deviceState != QAudio::ActiveState) { |
511 deviceState = QAudio::ActiveState; |
527 errorState = QAudio::NoError; |
512 } |
528 deviceState = QAudio::ActiveState; |
513 return l; |
529 emit stateChanged(deviceState); |
|
530 } |
|
531 return err; |
|
532 } |
514 } |
533 } |
515 return 0; |
534 return 0; |
516 } |
535 } |
517 |
536 |
518 void QAudioInputPrivate::resume() |
537 void QAudioInputPrivate::resume() |
532 bytesAvailable = buffer_size; |
551 bytesAvailable = buffer_size; |
533 } |
552 } |
534 resuming = true; |
553 resuming = true; |
535 deviceState = QAudio::ActiveState; |
554 deviceState = QAudio::ActiveState; |
536 int chunks = buffer_size/period_size; |
555 int chunks = buffer_size/period_size; |
537 timer->start(buffer_time*chunks/2000); |
556 timer->start(period_time*chunks/2000); |
538 emit stateChanged(deviceState); |
557 emit stateChanged(deviceState); |
539 } |
558 } |
540 } |
559 } |
541 |
560 |
542 void QAudioInputPrivate::setBufferSize(int value) |
561 void QAudioInputPrivate::setBufferSize(int value) |
615 return true; |
634 return true; |
616 } |
635 } |
617 |
636 |
618 qint64 QAudioInputPrivate::elapsedUSecs() const |
637 qint64 QAudioInputPrivate::elapsedUSecs() const |
619 { |
638 { |
620 if(!handle) |
|
621 return 0; |
|
622 |
|
623 if (deviceState == QAudio::StoppedState) |
639 if (deviceState == QAudio::StoppedState) |
624 return 0; |
640 return 0; |
625 |
641 |
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; |
642 return clockStamp.elapsed()*1000; |
647 #endif |
|
648 } |
643 } |
649 |
644 |
650 void QAudioInputPrivate::reset() |
645 void QAudioInputPrivate::reset() |
651 { |
646 { |
652 if(handle) |
647 if(handle) |
668 { |
663 { |
669 } |
664 } |
670 |
665 |
671 qint64 InputPrivate::readData( char* data, qint64 len) |
666 qint64 InputPrivate::readData( char* data, qint64 len) |
672 { |
667 { |
673 // push mode, user read() called |
668 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 } |
669 } |
711 |
670 |
712 qint64 InputPrivate::writeData(const char* data, qint64 len) |
671 qint64 InputPrivate::writeData(const char* data, qint64 len) |
713 { |
672 { |
714 Q_UNUSED(data) |
673 Q_UNUSED(data) |