本文实例为大家分享了iOS实现音乐播放器的具体代码,供大家参考,具体内容如下
audio_queue.cpp
#include "audio_queue.h" #include//#define AQ_DEBUG 1 #if !defined (AQ_DEBUG) #define AQ_TRACE(...) do {} while (0) #else #define AQ_TRACE(...) printf(__VA_ARGS__) #endif namespace astreamer { typedef struct queued_packet { AudioStreamPacketDescription desc; struct queued_packet *next; char data[]; } queued_packet_t; Audio_Queue::Audio_Queue() : m_delegate(0), m_state(IDLE), m_outAQ(0), m_fillBufferIndex(0), m_bytesFilled(0), m_packetsFilled(0), m_buffersUsed(0), m_processedPacketsSizeTotal(0), m_processedPacketsCount(0), m_audioQueueStarted(false), m_waitingonBuffer(false), m_queuedHead(0), m_queuedTail(0), m_lastError(noErr) { for (size_t i=0; i < AQ_BUFFERS; i++) { m_bufferInUse[i] = false; } } Audio_Queue::~Audio_Queue() { stop(true); cleanup(); } bool Audio_Queue::initialized() { return (m_outAQ != 0); } void Audio_Queue::start() { // start the queue if it has not been started already if (m_audioQueueStarted) { return; } OSStatus err = AudioQueueStart(m_outAQ, NULL); if (!err) { m_audioQueueStarted = true; m_lastError = noErr; } else { AQ_TRACE("%s: AudioQueueStart failed!n", __PRETTY_FUNCTION__); m_lastError = err; } } void Audio_Queue::pause() { if (m_state == RUNNING) { if (AudioQueuePause(m_outAQ) != 0) { AQ_TRACE("%s: AudioQueuePause failed!n", __PRETTY_FUNCTION__); } setState(PAUSED); } else if (m_state == PAUSED) { AudioQueueStart(m_outAQ, NULL); setState(RUNNING); } } void Audio_Queue::stop() { stop(true); } void Audio_Queue::stop(bool stopImmediately) { if (!m_audioQueueStarted) { AQ_TRACE("%s: audio queue already stopped, return!n", __PRETTY_FUNCTION__); return; } m_audioQueueStarted = false; AQ_TRACE("%s: entern", __PRETTY_FUNCTION__); if (AudioQueueFlush(m_outAQ) != 0) { AQ_TRACE("%s: AudioQueueFlush failed!n", __PRETTY_FUNCTION__); } if (stopImmediately) { AudioQueueRemovePropertyListener(m_outAQ, kAudioQueueProperty_IsRunning, audioQueueIsRunningCallback, this); } if (AudioQueueStop(m_outAQ, stopImmediately) != 0) { AQ_TRACE("%s: AudioQueueStop failed!n", __PRETTY_FUNCTION__); } if (stopImmediately) { setState(IDLE); } AQ_TRACE("%s: leaven", __PRETTY_FUNCTION__); } double Audio_Queue::packetDuration() { return m_streamDesc.mframesPerPacket / m_streamDesc.mSampleRate; } unsigned Audio_Queue::timePlayedInSeconds() { unsigned timePlayed = 0; AudioTimeStamp queueTime; Boolean discontinuity; OSStatus err = AudioQueueGetCurrentTime(m_outAQ, NULL, &queueTime, &discontinuity); if (err) { goto out; } timePlayed = queueTime.mSampleTime / m_streamDesc.mSampleRate; out: return timePlayed; } unsigned Audio_Queue::bitrate() { unsigned bitrate = 0; double packetDuration = this->packetDuration(); if (packetDuration > 0 && m_processedPacketsCount > 50) { double averagePacketByteSize = m_processedPacketsSizeTotal / m_processedPacketsCount; bitrate = 8 * averagePacketByteSize / packetDuration; } return bitrate; } void Audio_Queue::handlePropertyChange(AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags) { OSStatus err = noErr; AQ_TRACE("found property '%lu%lu%lu%lu'n", (inPropertyID>>24)&255, (inPropertyID>>16)&255, (inPropertyID>>8)&255, inPropertyID&255); switch (inPropertyID) { case kAudioFileStreamProperty_ReadyToProducePackets: { cleanup(); // the file stream parser is now ready to produce audio packets. // get the stream format. memset(&m_streamDesc, 0, sizeof(m_streamDesc)); UInt32 asbdSize = sizeof(m_streamDesc); err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &m_streamDesc); if (err) { AQ_TRACE("%s: error in kAudioFileStreamProperty_DataFormatn", __PRETTY_FUNCTION__); m_lastError = err; break; } // create the audio queue err = AudioQueueNewOutput(&m_streamDesc, audioQueueOutputCallback, this, CFRunLoopGetCurrent(), NULL, 0, &m_outAQ); if (err) { AQ_TRACE("%s: error in AudioQueueNewOutputn", __PRETTY_FUNCTION__); if (m_delegate) { m_delegate->audioQueueInitializationFailed(); } m_lastError = err; break; } // allocate audio queue buffers for (unsigned int i = 0; i < AQ_BUFFERS; ++i) { err = AudioQueueAllocateBuffer(m_outAQ, AQ_BUFSIZ, &m_audioQueueBuffer[i]); if (err) { AQ_TRACE("%s: error in AudioQueueAllocateBuffern", __PRETTY_FUNCTION__); (void)AudioQueueDispose(m_outAQ, true); m_outAQ = 0; if (m_delegate) { m_delegate->audioQueueInitializationFailed(); } m_lastError = err; break; } } setcookiesForStream(inAudioFileStream); // listen for kAudioQueueProperty_IsRunning err = AudioQueueAddPropertyListener(m_outAQ, kAudioQueueProperty_IsRunning, audioQueueIsRunningCallback, this); if (err) { AQ_TRACE("%s: error in AudioQueueAddPropertyListenern", __PRETTY_FUNCTION__); m_lastError = err; break; } break; } } } void Audio_Queue::handleAudioPackets(UInt32 inNumberBytes, UInt32 inNumberPackets, const void *inInputData, AudioStreamPacketDescription *inPacketDescriptions) { if (!initialized()) { AQ_TRACE("%s: warning: attempt to handle audio packets with uninitialized audio queue. return.n", __PRETTY_FUNCTION__); return; } // this is called by audio file stream when it finds packets of audio AQ_TRACE("got data. bytes: %lu packets: %lun", inNumberBytes, inNumberPackets); UInt32 i; if (!inPacketDescriptions) { AQ_TRACE("%s: notice: supplying the packet descriptions for a supposed CBR data.n", __PRETTY_FUNCTION__); // If no packet descriptions are supplied, assume we are dealing with CBR data UInt32 base = inNumberBytes / inNumberPackets; AudioStreamPacketDescription *descriptions = new AudioStreamPacketDescription[inNumberPackets]; for (i = 0; i < inNumberPackets; i++) { descriptions[i].mStartOffset = (base * i); descriptions[i].mDataByteSize = base; descriptions[i].mVariableframesInPacket = 0; } inPacketDescriptions = descriptions; m_cbrPacketDescriptions.push_back(descriptions); } for (i = 0; i < inNumberPackets && !m_waitingonBuffer && m_queuedHead == NULL; i++) { AudioStreamPacketDescription *desc = &inPacketDescriptions[i]; int ret = handlePacket((const char*)inInputData + desc->mStartOffset, desc); if (!ret) break; } if (i == inNumberPackets) { return; } for (; i < inNumberPackets; i++) { UInt32 size = inPacketDescriptions[i].mDataByteSize; queued_packet_t *packet = (queued_packet_t *)malloc(sizeof(queued_packet_t) + size); packet->next = NULL; packet->desc = inPacketDescriptions[i]; packet->desc.mStartOffset = 0; memcpy(packet->data, (const char *)inInputData + inPacketDescriptions[i].mStartOffset, size); if (m_queuedHead == NULL) { m_queuedHead = m_queuedTail = packet; } else { m_queuedTail->next = packet; m_queuedTail = packet; } } } int Audio_Queue::handlePacket(const void *data, AudioStreamPacketDescription *desc) { if (!initialized()) { AQ_TRACE("%s: warning: attempt to handle audio packets with uninitialized audio queue. return.n", __PRETTY_FUNCTION__); return -1; } AQ_TRACE("%s: entern", __PRETTY_FUNCTION__); UInt32 packetSize = desc->mDataByteSize; if (packetSize > AQ_BUFSIZ) { AQ_TRACE("%s: packetSize %lli > AQ_BUFSIZ %lin", __PRETTY_FUNCTION__, packetSize, AQ_BUFSIZ); return -1; } // if the space remaining in the buffer is not enough for this packet, then // enqueue the buffer and wait for another to become available. if (AQ_BUFSIZ - m_bytesFilled < packetSize) { int hasFreeBuffer = enqueueBuffer(); if (hasFreeBuffer <= 0) { return hasFreeBuffer; } } else { AQ_TRACE("%s: skipped enqueueBuffer AQ_BUFSIZ - m_bytesFilled %lu, packetSize %llin", __PRETTY_FUNCTION__, (AQ_BUFSIZ - m_bytesFilled), packetSize); } m_processedPacketsSizeTotal += packetSize; m_processedPacketsCount++; // copy data to the audio queue buffer AudioQueueBufferRef buf = m_audioQueueBuffer[m_fillBufferIndex]; memcpy((char*)buf->mAudioData + m_bytesFilled, data, packetSize); // fill out packet description to pass to enqueue() later on m_packetDescs[m_packetsFilled] = *desc; // Make sure the offset is relative to the start of the audio buffer m_packetDescs[m_packetsFilled].mStartOffset = m_bytesFilled; // keep track of bytes filled and packets filled m_bytesFilled += packetSize; m_packetsFilled++; #define kAQMaxPacketDescs 512 if (m_packetsFilled >= kAQMaxPacketDescs) { return enqueueBuffer(); } return 1; } void Audio_Queue::cleanup() { if (!initialized()) { AQ_TRACE("%s: warning: attempt to cleanup an uninitialized audio queue. return.n", __PRETTY_FUNCTION__); return; } if (AudioQueueDispose(m_outAQ, true) != 0) { AQ_TRACE("%s: AudioQueueDispose failed!n", __PRETTY_FUNCTION__); } m_outAQ = 0; m_fillBufferIndex = m_bytesFilled = m_packetsFilled = m_buffersUsed = m_processedPacketsSizeTotal = m_processedPacketsCount = 0; for (size_t i=0; i < AQ_BUFFERS; i++) { m_bufferInUse[i] = false; } queued_packet_t *cur = m_queuedHead; while (cur) { queued_packet_t *tmp = cur->next; free(cur); cur = tmp; } m_queuedHead = m_queuedHead = 0; for (size_t i=0; i < m_cbrPacketDescriptions.size(); i++) { delete[] m_cbrPacketDescriptions[i]; } m_cbrPacketDescriptions.clear(); m_waitingonBuffer = false; m_lastError = noErr; } void Audio_Queue::setcookiesForStream(AudioFileStreamID inAudioFileStream) { OSStatus err; // get the cookie size UInt32 cookieSize; Boolean writable; err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagiccookieData, &cookieSize, &writable); if (err) { AQ_TRACE("error in info kAudioFileStreamProperty_MagiccookieDatan"); return; } AQ_TRACE("cookieSize %lun", cookieSize); // get the cookie data void* cookieData = calloc(1, cookieSize); err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagiccookieData, &cookieSize, cookieData); if (err) { AQ_TRACE("error in get kAudioFileStreamProperty_MagiccookieData"); free(cookieData); return; } // set the cookie on the queue. err = AudioQueueSetProperty(m_outAQ, kAudioQueueProperty_Magiccookie, cookieData, cookieSize); free(cookieData); if (err) { AQ_TRACE("error in set kAudioQueueProperty_Magiccookie"); } } void Audio_Queue::setState(State state) { if (m_state == state) { return; } m_state = state; if (m_delegate) { m_delegate->audioQueueStateChanged(m_state); } } int Audio_Queue::enqueueBuffer() { assert(!m_bufferInUse[m_fillBufferIndex]); AQ_TRACE("%s: entern", __PRETTY_FUNCTION__); m_bufferInUse[m_fillBufferIndex] = true; m_buffersUsed++; // enqueue buffer AudioQueueBufferRef fillBuf = m_audioQueueBuffer[m_fillBufferIndex]; fillBuf->mAudioDataByteSize = m_bytesFilled; assert(m_packetsFilled > 0); OSStatus err = AudioQueueEnqueueBuffer(m_outAQ, fillBuf, m_packetsFilled, m_packetDescs); if (!err) { m_lastError = noErr; start(); } else { AQ_TRACE("%s: error in AudioQueueEnqueueBuffern", __PRETTY_FUNCTION__); m_lastError = err; return 1; } // go to next buffer if (++m_fillBufferIndex >= AQ_BUFFERS) { m_fillBufferIndex = 0; } // reset bytes filled m_bytesFilled = 0; // reset packets filled m_packetsFilled = 0; // wait until next buffer is not in use if (m_bufferInUse[m_fillBufferIndex]) { AQ_TRACE("waiting for buffer %lun", m_fillBufferIndex); if (m_delegate) { m_delegate->audioQueueOverflow(); } m_waitingonBuffer = true; return 0; } return 1; } int Audio_Queue::findQueueBuffer(AudioQueueBufferRef inBuffer) { for (unsigned int i = 0; i < AQ_BUFFERS; ++i) { if (inBuffer == m_audioQueueBuffer[i]) { AQ_TRACE("findQueueBuffer %in", i); return i; } } return -1; } void Audio_Queue::enqueueCachedData() { assert(!m_waitingOnBuffer); assert(!m_bufferInUse[m_fillBufferIndex]); queued_packet_t *cur = m_queuedHead; while (cur) { int ret = handlePacket(cur->data, &cur->desc); if (ret == 0) { break; } queued_packet_t *next = cur->next; free(cur); cur = next; } m_queuedHead = cur; if (cur == NULL) { m_queuedTail = NULL; if (m_delegate) { m_delegate->audioQueueUnderflow(); } } } // this is called by the audio queue when it has finished decoding our data. // The buffer is now free to be reused. void Audio_Queue::audioQueueOutputCallback(void *inClientData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { Audio_Queue *audioQueue = static_cast(inClientData); unsigned int bufIndex = audioQueue->findQueueBuffer(inBuffer); assert(audioQueue->m_bufferInUse[bufIndex]); audioQueue->m_bufferInUse[bufIndex] = false; audioQueue->m_buffersUsed--; if (audioQueue->m_buffersUsed == 0 && !audioQueue->m_queuedHead && audioQueue->m_delegate) { audioQueue->m_delegate->audioQueueBuffersEmpty(); } else if (audioQueue->m_waitingOnBuffer) { audioQueue->m_waitingonBuffer = false; audioQueue->enqueueCachedData(); } } void Audio_Queue::audioQueueIsRunningCallback(void *inClientData, AudioQueueRef inAQ, AudioQueuePropertyID inID) { Audio_Queue *audioQueue = static_cast(inClientData); AQ_TRACE("%s: entern", __PRETTY_FUNCTION__); UInt32 running; UInt32 output = sizeof(running); OSStatus err = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &running, &output); if (err) { AQ_TRACE("%s: error in kAudioQueueProperty_IsRunningn", __PRETTY_FUNCTION__); return; } if (running) { AQ_TRACE("audio queue running!n"); audioQueue->setState(RUNNING); } else { audioQueue->setState(IDLE); } } } // namespace astreamer
audio_stream.h
#ifndef ASTREAMER_AUDIO_STREAM_H #define ASTREAMER_AUDIO_STREAM_H #import "http_stream.h" #include "audio_queue.h" #include #includenamespace astreamer { enum Audio_Stream_Error { AS_ERR_OPEN = 1, // Cannot open the audio stream AS_ERR_STREAM_PARSE = 2, // Parse error AS_ERR_NETWORK = 3 // Network error }; class Audio_Stream_Delegate; class Audio_Stream : public HTTP_Stream_Delegate, public Audio_Queue_Delegate { public: Audio_Stream_Delegate *m_delegate; enum State { STOPPED, BUFFERING, PLAYING, SEEKING, FAILED, END_OF_FILE }; Audio_Stream(); virtual ~Audio_Stream(); void open(); void close(); void pause(); unsigned timePlayedInSeconds(); unsigned durationInSeconds(); void seekToTime(unsigned newSeekTime); void setUrl(CFURLRef url); void setStrictContentTypeChecking(bool strictChecking); void setDefaultContentType(std::string& defaultContentType); State state(); void audioQueueStateChanged(Audio_Queue::State state); void audioQueueBuffersEmpty(); void audioQueueOverflow(); void audioQueueUnderflow(); void audioQueueInitializationFailed(); void streamIsReadyRead(); void streamHasBytesAvailable(UInt8 *data, UInt32 numBytes); void streamEndEncountered(); void streamErrorOccurred(); void streammetaDataAvailable(std::map metaData); private: Audio_Stream(const Audio_Stream&); Audio_Stream& operator=(const Audio_Stream&); bool m_httpStreamRunning; bool m_audioStreamParserRunning; size_t m_contentLength; State m_state; HTTP_Stream *m_httpStream; Audio_Queue *m_audioQueue; AudioFileStreamID m_audioFileStream; // the audio file stream parser SInt64 m_dataOffset; unsigned m_seekTime; bool m_strictContentTypeChecking; std::string m_defaultContentType; size_t contentLength(); void closeAndSignalError(int error); void setState(State state); static void propertyValueCallback(void *inClientData, AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags); static void streamDataCallback(void *inClientData, UInt32 inNumberBytes, UInt32 inNumberPackets, const void *inInputData, AudioStreamPacketDescription *inPacketDescriptions); AudioFileTypeID audioStreamTypeFromContentType(std::string contentType); }; class Audio_Stream_Delegate { public: virtual void audioStreamStateChanged(Audio_Stream::State state) = 0; virtual void audioStreamErrorOccurred(int errorCode) = 0; virtual void audioStreammetaDataAvailable(std::map metaData) = 0; }; } // namespace astreamer #endif // ASTREAMER_AUDIO_STREAM_H
更多源码请点击下载:iOS音乐播放器实现代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



