예제 #1
0
/*----------------------------------------------------------------------
|    AlsaOutput_PutPacket
+---------------------------------------------------------------------*/
BLT_METHOD
AlsaOutput_PutPacket(BLT_PacketConsumer* _self,
                     BLT_MediaPacket*    packet)
{
    AlsaOutput*             self = ATX_SELF(AlsaOutput, BLT_PacketConsumer);
    const BLT_PcmMediaType* media_type;
    BLT_ByteBuffer          buffer;
    BLT_Size                size;
    BLT_Result              result;

    /* check parameters */
    if (packet == NULL) {
        return BLT_ERROR_INVALID_PARAMETERS;
    }

    /* check the payload buffer and size */
    buffer = BLT_MediaPacket_GetPayloadBuffer(packet);
    size = BLT_MediaPacket_GetPayloadSize(packet);
    if (size == 0) return BLT_SUCCESS;

    /* get the media type */
    result = BLT_MediaPacket_GetMediaType(packet, (const BLT_MediaType**)(const void*)&media_type);
    if (BLT_FAILED(result)) return result;

    /* check the media type */
    if (media_type->base.id != BLT_MEDIA_TYPE_ID_AUDIO_PCM) {
        return BLT_ERROR_INVALID_MEDIA_TYPE;
    }

    /* configure the device for this format */
    result = AlsaOutput_Configure(self, media_type);
	if (BLT_FAILED(result)) return result;
	
    /* update the media time */
    {
        BLT_TimeStamp ts = BLT_MediaPacket_GetTimeStamp(packet);
        ATX_UInt64    ts_nanos = BLT_TimeStamp_ToNanos(ts);
        BLT_TimeStamp packet_duration;
        if (media_type->sample_rate   && 
            media_type->channel_count && 
            media_type->bits_per_sample) {
            unsigned int sample_count = BLT_MediaPacket_GetPayloadSize(packet)/
                                        (media_type->channel_count*media_type->bits_per_sample/8);
            packet_duration = BLT_TimeStamp_FromSamples(sample_count, media_type->sample_rate);            
        } else {
            packet_duration = BLT_TimeStamp_FromSeconds(0);
        }
        if (ts_nanos == 0) {
            self->media_time = self->next_media_time;
        } else {
            self->media_time = ts_nanos;
        }
        self->next_media_time = self->media_time+BLT_TimeStamp_ToNanos(packet_duration);
    }
    
    /* write the audio samples */
    return AlsaOutput_Write(self, buffer, size);
}
예제 #2
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_RenderCallback
+---------------------------------------------------------------------*/
static OSStatus     
OsxAudioUnitsOutput_RenderCallback(void*						inRefCon,
                                   AudioUnitRenderActionFlags*	ioActionFlags,
                                   const AudioTimeStamp*		inTimeStamp,
                                   UInt32						inBusNumber,
                                   UInt32						inNumberFrames,
                                   AudioBufferList*			    ioData)
{
    OsxAudioUnitsOutput* self = (OsxAudioUnitsOutput*)inRefCon;
    ATX_ListItem*        item;
    unsigned int         requested;
    unsigned char*       out;
    ATX_Boolean          timestamp_measured = ATX_FALSE;
    
    BLT_COMPILER_UNUSED(ioActionFlags);
    BLT_COMPILER_UNUSED(inTimeStamp);
    BLT_COMPILER_UNUSED(inBusNumber);
    BLT_COMPILER_UNUSED(inNumberFrames);
                
    /* sanity check on the parameters */
    if (ioData == NULL || ioData->mNumberBuffers == 0) return 0;
    
    /* in case we have a strange request with more than one buffer, just return silence */
    if (ioData->mNumberBuffers != 1) {
        unsigned int i;
        ATX_LOG_FINEST_1("strange request with %d buffers", 
                         (int)ioData->mNumberBuffers);
        for (i=0; i<ioData->mNumberBuffers; i++) {
            ATX_SetMemory(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
        }
        return 0;
    }
        
    /* init local variables */
    requested = ioData->mBuffers[0].mDataByteSize;
    out = (unsigned char*)ioData->mBuffers[0].mData;
    ATX_LOG_FINEST_2("request for %d bytes, %d frames", (int)requested, (int)inNumberFrames);

    /* lock the packet queue */
    pthread_mutex_lock(&self->lock);
    
    /* return now if we're paused */
    //if (self->paused) goto end;
    
    /* abort early if we have no packets */
    if (ATX_List_GetItemCount(self->packet_queue) == 0) goto end;
        
    /* fill as much as we can */
    while (requested && (item = ATX_List_GetFirstItem(self->packet_queue))) {
        BLT_MediaPacket*        packet = ATX_ListItem_GetData(item);
        const BLT_PcmMediaType* media_type;
        BLT_Size                payload_size;
        BLT_Size                chunk_size;
        BLT_TimeStamp           chunk_duration;
        BLT_TimeStamp           packet_ts;
        unsigned int            bytes_per_frame;
        unsigned int            sample_rate;
        
        /* get the packet info */
        BLT_MediaPacket_GetMediaType(packet, (const BLT_MediaType**)&media_type);
        packet_ts = BLT_MediaPacket_GetTimeStamp(packet);
        bytes_per_frame = media_type->channel_count*media_type->bits_per_sample/8;
        sample_rate = media_type->sample_rate;
        
        /* record the timestamp if we have not already done so */
        if (!timestamp_measured) {
            self->media_time_snapshot.rendered_packet_ts = packet_ts;
            self->media_time_snapshot.rendered_host_time = 
                AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
            BLT_TimeStamp_Set(self->media_time_snapshot.rendered_duration, 0, 0);
            timestamp_measured = ATX_TRUE;
            
            ATX_LOG_FINEST_2("rendered TS: packet ts=%lld, host ts=%lld",
                             BLT_TimeStamp_ToNanos(packet_ts),
                             self->media_time_snapshot.rendered_host_time);
        }
         
        /* compute how much to copy from this packet */
        payload_size = BLT_MediaPacket_GetPayloadSize(packet);
        if (payload_size <= requested) {
            /* copy the entire payload and remove the packet from the queue */
            chunk_size = payload_size;
            ATX_CopyMemory(out, BLT_MediaPacket_GetPayloadBuffer(packet), chunk_size);
            ATX_List_RemoveItem(self->packet_queue, item);
            packet = NULL;
            media_type = NULL;
            ATX_LOG_FINER_1("media packet fully consumed, %d left in queue",
                            ATX_List_GetItemCount(self->packet_queue));
        } else {
            /* only copy a portion of the payload */
            chunk_size = requested;
            ATX_CopyMemory(out, BLT_MediaPacket_GetPayloadBuffer(packet), chunk_size);            
        }
        
        /* update the counters */
        requested -= chunk_size;
        out       += chunk_size;
        
        /* update the media time snapshot */
        if (bytes_per_frame) {
            unsigned int frames_in_chunk = chunk_size/bytes_per_frame;
            chunk_duration = BLT_TimeStamp_FromSamples(frames_in_chunk, sample_rate);
        } else {
            BLT_TimeStamp_Set(chunk_duration, 0, 0);
        }
        self->media_time_snapshot.rendered_duration = 
            BLT_TimeStamp_Add(self->media_time_snapshot.rendered_duration, chunk_duration);
        
        /* update the packet unless we're done with it */
        if (packet) {
            /* update the packet offset and timestamp */
            BLT_MediaPacket_SetPayloadOffset(packet, BLT_MediaPacket_GetPayloadOffset(packet)+chunk_size);
            BLT_MediaPacket_SetTimeStamp(packet, BLT_TimeStamp_Add(packet_ts, chunk_duration));
        }
    }
   
end:
    /* fill whatever is left with silence */    
    if (requested) {
        ATX_LOG_FINEST_1("filling with %d bytes of silence", requested);
        ATX_SetMemory(out, 0, requested);
    }
    
    pthread_mutex_unlock(&self->lock);
        
    return 0;
}