mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
ffmpeg audio play / capture done in os x
This commit is contained in:
parent
1b11a7feae
commit
1b06fe1220
6 changed files with 98 additions and 48 deletions
|
@ -30,6 +30,30 @@ extern "C" {
|
|||
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <iconv.h>
|
||||
|
||||
#undef iconv_open
|
||||
#undef iconv
|
||||
#undef iconv_close
|
||||
|
||||
iconv_t iconv_open (const char* tocode, const char* fromcode) {
|
||||
return libiconv_open(tocode, fromcode);
|
||||
}
|
||||
size_t iconv (iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft) {
|
||||
return libiconv(cd, inbuf, inbytesleft, outbuf, outbytesleft);
|
||||
}
|
||||
int iconv_close (iconv_t cd) {
|
||||
return libiconv_close(cd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
ALCdevice *audioDevice = 0;
|
||||
ALCcontext *audioContext = 0;
|
||||
|
@ -285,48 +309,53 @@ bool AudioPlayer::updateCurrentStarted(int32 pos) {
|
|||
}
|
||||
|
||||
void AudioPlayer::play(AudioData *audio) {
|
||||
QMutexLocker lock(&playerMutex);
|
||||
AudioData *stopped = 0;
|
||||
|
||||
bool startNow = true;
|
||||
if (_data[_current].audio != audio) {
|
||||
switch (_data[_current].state) {
|
||||
case AudioPlayerStarting:
|
||||
case AudioPlayerResuming:
|
||||
case AudioPlayerPlaying:
|
||||
_data[_current].state = AudioPlayerFinishing;
|
||||
updateCurrentStarted();
|
||||
startNow = false;
|
||||
break;
|
||||
case AudioPlayerPausing: _data[_current].state = AudioPlayerFinishing; startNow = false; break;
|
||||
case AudioPlayerPaused: _data[_current].state = AudioPlayerStopped; break;
|
||||
}
|
||||
if (_data[_current].audio) {
|
||||
emit loaderOnCancel(_data[_current].audio);
|
||||
emit faderOnTimer();
|
||||
}
|
||||
}
|
||||
{
|
||||
QMutexLocker lock(&playerMutex);
|
||||
|
||||
int32 index = 0;
|
||||
for (; index < AudioVoiceMsgSimultaneously; ++index) {
|
||||
if (_data[index].audio == audio) {
|
||||
_current = index;
|
||||
break;
|
||||
bool startNow = true;
|
||||
if (_data[_current].audio != audio) {
|
||||
switch (_data[_current].state) {
|
||||
case AudioPlayerStarting:
|
||||
case AudioPlayerResuming:
|
||||
case AudioPlayerPlaying:
|
||||
_data[_current].state = AudioPlayerFinishing;
|
||||
updateCurrentStarted();
|
||||
startNow = false;
|
||||
break;
|
||||
case AudioPlayerPausing: _data[_current].state = AudioPlayerFinishing; startNow = false; break;
|
||||
case AudioPlayerPaused: _data[_current].state = AudioPlayerStopped; stopped = _data[_current].audio; break;
|
||||
}
|
||||
if (_data[_current].audio) {
|
||||
emit loaderOnCancel(_data[_current].audio);
|
||||
emit faderOnTimer();
|
||||
}
|
||||
}
|
||||
|
||||
int32 index = 0;
|
||||
for (; index < AudioVoiceMsgSimultaneously; ++index) {
|
||||
if (_data[index].audio == audio) {
|
||||
_current = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == AudioVoiceMsgSimultaneously && ++_current >= AudioVoiceMsgSimultaneously) {
|
||||
_current -= AudioVoiceMsgSimultaneously;
|
||||
}
|
||||
_data[_current].audio = audio;
|
||||
_data[_current].fname = audio->already(true);
|
||||
_data[_current].data = audio->data;
|
||||
if (_data[_current].fname.isEmpty() && _data[_current].data.isEmpty()) {
|
||||
_data[_current].state = AudioPlayerStopped;
|
||||
onError(audio);
|
||||
} else if (updateCurrentStarted(0)) {
|
||||
_data[_current].state = startNow ? AudioPlayerPlaying : AudioPlayerStarting;
|
||||
_data[_current].loading = true;
|
||||
emit loaderOnStart(audio);
|
||||
}
|
||||
}
|
||||
if (index == AudioVoiceMsgSimultaneously && ++_current >= AudioVoiceMsgSimultaneously) {
|
||||
_current -= AudioVoiceMsgSimultaneously;
|
||||
}
|
||||
_data[_current].audio = audio;
|
||||
_data[_current].fname = audio->already(true);
|
||||
_data[_current].data = audio->data;
|
||||
if (_data[_current].fname.isEmpty() && _data[_current].data.isEmpty()) {
|
||||
_data[_current].state = AudioPlayerStopped;
|
||||
onError(audio);
|
||||
} else if (updateCurrentStarted(0)) {
|
||||
_data[_current].state = startNow ? AudioPlayerPlaying : AudioPlayerStarting;
|
||||
_data[_current].loading = true;
|
||||
emit loaderOnStart(audio);
|
||||
}
|
||||
if (stopped) emit updated(stopped);
|
||||
}
|
||||
|
||||
void AudioPlayer::pauseresume() {
|
||||
|
@ -491,7 +520,7 @@ void AudioPlayerFader::onTimer() {
|
|||
emit audioStopped(m.audio);
|
||||
}
|
||||
}
|
||||
if (pos + m.skipStart - m.position >= AudioCheckPositionDelta) {
|
||||
if (state == AL_PLAYING && pos + m.skipStart - m.position >= AudioCheckPositionDelta) {
|
||||
m.position = pos + m.skipStart;
|
||||
emit playPositionUpdated(m.audio);
|
||||
}
|
||||
|
@ -739,7 +768,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
if (avpkt.stream_index == streamId) {
|
||||
avcodec_get_frame_defaults(frame);
|
||||
av_frame_unref(frame);
|
||||
int got_frame = 0;
|
||||
if ((res = avcodec_decode_audio4(codecContext, frame, &got_frame, &avpkt)) < 0) {
|
||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
|
@ -800,7 +829,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
int32 freq, fmt, channels;
|
||||
int32 freq, fmt;
|
||||
int32 sampleSize, srcRate, dstRate, maxResampleSamples;
|
||||
uint8_t **dstSamplesData;
|
||||
int64 len;
|
||||
|
@ -1054,6 +1083,8 @@ void AudioPlayerLoaders::onLoad(AudioData *audio) {
|
|||
if (finished) {
|
||||
m.skipEnd = 0;
|
||||
m.duration = m.skipStart + m.samplesCount[0] + m.samplesCount[1] + m.samplesCount[2];
|
||||
delete j.value();
|
||||
_loaders.erase(j);
|
||||
}
|
||||
m.loading = false;
|
||||
if (m.state == AudioPlayerResuming || m.state == AudioPlayerPlaying || m.state == AudioPlayerStarting) {
|
||||
|
@ -1172,7 +1203,7 @@ void AudioCaptureInner::onStart() {
|
|||
|
||||
// Start OpenAL Capture
|
||||
|
||||
d->device = alcCaptureOpenDevice(0, AudioVoiceMsgFrequency, AL_FORMAT_MONO16, AudioVoiceMsgBufferSize);
|
||||
d->device = alcCaptureOpenDevice(0, AudioVoiceMsgFrequency, AL_FORMAT_MONO16, AudioVoiceMsgFrequency / 5);
|
||||
if (!d->device) {
|
||||
LOG(("Audio Error: capture device not present!"));
|
||||
emit error();
|
||||
|
@ -1457,7 +1488,7 @@ void AudioCaptureInner::onTimeout() {
|
|||
}
|
||||
// Write frames
|
||||
int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0;
|
||||
while (_captured.size() >= encoded + framesize + fadeSamples * sizeof(short)) {
|
||||
while (uint32(_captured.size()) >= encoded + framesize + fadeSamples * sizeof(short)) {
|
||||
writeFrame(encoded, framesize);
|
||||
encoded += framesize;
|
||||
}
|
||||
|
@ -1527,8 +1558,9 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
|
|||
|
||||
// Write audio frame
|
||||
|
||||
AVPacket pkt = { 0 }; // data and size must be 0;
|
||||
AVFrame *frame = avcodec_alloc_frame();
|
||||
AVPacket pkt;
|
||||
memset(&pkt, 0, sizeof(pkt)); // data and size must be 0;
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
int gotPacket;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
|
@ -1552,5 +1584,5 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
|
|||
}
|
||||
d->fullSamples += samplesCnt;
|
||||
|
||||
avcodec_free_frame(&frame);
|
||||
av_frame_free(&frame);
|
||||
}
|
|
@ -35,6 +35,9 @@ enum AudioPlayerState {
|
|||
AudioPlayerResuming,
|
||||
};
|
||||
|
||||
class AudioPlayerFader;
|
||||
class AudioPlayerLoaders;
|
||||
|
||||
class AudioPlayer : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -104,6 +107,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class AudioCaptureInner;
|
||||
|
||||
class AudioCapture : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -199,6 +204,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct AudioCapturePrivate;
|
||||
|
||||
class AudioCaptureInner : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -225,7 +232,6 @@ private:
|
|||
|
||||
void writeFrame(int32 offset, int32 framesize);
|
||||
|
||||
friend struct AudioCapturePrivate;
|
||||
AudioCapturePrivate *d;
|
||||
QTimer _timer;
|
||||
QByteArray _captured;
|
||||
|
|
|
@ -3031,6 +3031,7 @@ void HistoryWidget::stopRecording(bool send) {
|
|||
_recordingAnim.stop();
|
||||
|
||||
_recording = false;
|
||||
_recordingSamples = 0;
|
||||
updateControlsVisibility();
|
||||
activate();
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ typedef QList<ToPrepareMedia> ToPrepareMedias;
|
|||
typedef QMap<int32, QByteArray> LocalFileParts;
|
||||
struct ReadyLocalMedia {
|
||||
ReadyLocalMedia(ToPrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const MTPAudio &audio, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool ctrlShiftEnter, MsgId replyTo) :
|
||||
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), photoThumbs(photoThumbs), audio(audio), ctrlShiftEnter(ctrlShiftEnter) {
|
||||
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), audio(audio), photoThumbs(photoThumbs), ctrlShiftEnter(ctrlShiftEnter) {
|
||||
if (!jpeg.isEmpty()) {
|
||||
int32 size = jpeg.size();
|
||||
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
|
||||
|
|
|
@ -1863,6 +1863,11 @@
|
|||
/usr/local/lib/libmpg123.a,
|
||||
/usr/local/lib/libfaad.a,
|
||||
/usr/local/lib/libmp4ff.a,
|
||||
/usr/local/lib/libavcodec.a,
|
||||
/usr/local/lib/libavformat.a,
|
||||
/usr/local/lib/libswresample.a,
|
||||
/usr/local/lib/libavutil.a,
|
||||
/usr/local/lib/libiconv.a,
|
||||
"../../Libraries/openssl-xcode/libcrypto.a",
|
||||
);
|
||||
PRODUCT_NAME = Telegram;
|
||||
|
@ -2010,6 +2015,11 @@
|
|||
/usr/local/lib/libmpg123.a,
|
||||
/usr/local/lib/libfaad.a,
|
||||
/usr/local/lib/libmp4ff.a,
|
||||
/usr/local/lib/libavcodec.a,
|
||||
/usr/local/lib/libavformat.a,
|
||||
/usr/local/lib/libswresample.a,
|
||||
/usr/local/lib/libavutil.a,
|
||||
/usr/local/lib/libiconv.a,
|
||||
"../../Libraries/openssl-xcode/libcrypto.a",
|
||||
);
|
||||
PRODUCT_NAME = Telegram;
|
||||
|
|
|
@ -131,6 +131,7 @@ GeneratedFiles/Debug/moc_application.cpp: ../../Libraries/QtStatic/qtbase/includ
|
|||
/usr/local/Qt-5.4.0/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.4.0/mkspecs/macx-clang -I. -I/usr/local/Qt-5.4.0/include/QtGui/5.4.0/QtGui -I/usr/local/Qt-5.4.0/include/QtCore/5.4.0/QtCore -I/usr/local/Qt-5.4.0/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.4.0/include -I/usr/local/Qt-5.4.0/include/QtMultimedia -I/usr/local/Qt-5.4.0/include/QtWidgets -I/usr/local/Qt-5.4.0/include/QtNetwork -I/usr/local/Qt-5.4.0/include/QtGui -I/usr/local/Qt-5.4.0/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/application.h -o GeneratedFiles/Debug/moc_application.cpp
|
||||
|
||||
GeneratedFiles/Debug/moc_audio.cpp: SourceFiles/types.h \
|
||||
SourceFiles/audio.h \
|
||||
../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \
|
||||
SourceFiles/logs.h \
|
||||
../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \
|
||||
|
|
Loading…
Add table
Reference in a new issue