/*----------------------------------------------------------------------
|    AlsaOutput_Close
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Close(AlsaOutput* self)
{
    ATX_LOG_FINER("closing output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* wait for buffers to finish */
        ATX_LOG_FINER("snd_pcm_drain");
        snd_pcm_drain(self->device_handle);
        /* FALLTHROUGH */

      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* close the device */
        ATX_LOG_FINER("snd_pcm_close");
        snd_pcm_close(self->device_handle);
        self->device_handle = NULL;
        break;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CLOSED);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Drain
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Drain(BLT_OutputNode* _self)
{
    OsxAudioUnitsOutput* self = ATX_SELF(OsxAudioUnitsOutput, BLT_OutputNode);
    unsigned int watchdog = 20000000/BLT_OSX_AUDIO_UNITS_OUTPUT_SLEEP_INTERVAL;
    
    ATX_LOG_FINER("draining packets"); 

    /* lock the queue */
    pthread_mutex_lock(&self->lock);
    
    /* wait until there are no more packets in the queue */
    while (ATX_List_GetItemCount(self->packet_queue)) {
        pthread_mutex_unlock(&self->lock);
        ATX_LOG_FINER("waiting..."); 
        usleep(BLT_OSX_AUDIO_UNITS_OUTPUT_SLEEP_INTERVAL);
        pthread_mutex_lock(&self->lock);
        
        if (--watchdog == 0) {
            ATX_LOG_WARNING("*** the watchdog bit us ***");
            break;
        }
    }

    /* unlock the queue */
    pthread_mutex_unlock(&self->lock);
    
    ATX_LOG_FINER("end"); 

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    WaveFormatter_Deactivate
+---------------------------------------------------------------------*/
BLT_METHOD
WaveFormatter_Deactivate(BLT_MediaNode* _self)
{
    WaveFormatter* self = ATX_SELF_EX(WaveFormatter, BLT_BaseMediaNode, BLT_MediaNode);

    ATX_LOG_FINER("WaveFormatter::Deactivate");

    /* update the header if needed */
    if (self->output.stream) {
        ATX_Position where = 0;
        ATX_OutputStream_Tell(self->output.stream, &where);
        self->input.size = where;
        if (self->input.size >= BLT_WAVE_FORMATTER_RIFF_HEADER_SIZE) {
            self->input.size -= BLT_WAVE_FORMATTER_RIFF_HEADER_SIZE;
        }

        /* update the header */
        WaveFormatter_UpdateWavHeader(self);

        /* set the stream back to its original position */
        ATX_OutputStream_Seek(self->output.stream, where);
    }

    /* release the output stream */
    ATX_RELEASE_OBJECT(self->output.stream);

    /* call the base class method */
    BLT_BaseMediaNode_Deactivate(_self);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    SilenceRemover_TrimPending
+---------------------------------------------------------------------*/
static void
SilenceRemover_TrimPending(SilenceRemover* self)
{
    BLT_MediaPacket* packet = self->input.pending;
    short*           pcm;
    BLT_Cardinal     sample_count;
    BLT_Cardinal     skip = 0;
    int              sample;

    /* quick check */
    if (!packet) return;

    ATX_LOG_FINER("SilenceRemover: trimming pending packet");

    /* remove silence at the end of the packet */
    pcm = (short*)BLT_MediaPacket_GetPayloadBuffer(packet);
    sample_count = BLT_MediaPacket_GetPayloadSize(packet)/4;
    pcm += sample_count*2;
    for (sample = sample_count-1; sample >= 0; sample--, pcm-=2) {
        if (pcm[0] > -BLT_SILENCE_REMOVER_THRESHOLD && 
            pcm[0] <  BLT_SILENCE_REMOVER_THRESHOLD && 
            pcm[1] > -BLT_SILENCE_REMOVER_THRESHOLD && 
            pcm[1] <  BLT_SILENCE_REMOVER_THRESHOLD) {
            skip++;
        }
    }
    BLT_MediaPacket_SetPayloadSize(packet, (sample_count-skip)*4);
}
Exemple #5
0
/*----------------------------------------------------------------------
|    AlsaOutput_Unprepare
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Unprepare(AlsaOutput* self)
{
    BLT_Result result;

    ATX_LOG_FINER("unpreparing output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        break;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* drain any pending samples */
        result = AlsaOutput_Drain(self);
        if (BLT_FAILED(result)) return result;
        
        /* update the state */
        AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);
        break;
    }

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    AlsaOutput_Open
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Open(AlsaOutput* self)
{
    int io_result;

    ATX_LOG_FINE_1("openning output - name=%s", ATX_CSTR(self->device_name));

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
        ATX_LOG_FINER("snd_pcm_open");
        io_result = snd_pcm_open(&self->device_handle,
                                 ATX_CSTR(self->device_name),
                                 SND_PCM_STREAM_PLAYBACK,
                                 0);
        if (io_result != 0) {
            self->device_handle = NULL;
            return BLT_FAILURE;
        }
        break;

      case BLT_ALSA_OUTPUT_STATE_OPEN:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        return BLT_FAILURE;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_OPEN);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::SetInput
+---------------------------------------------------------------------*/
BLT_Result 
BLT_DecoderServer::SetInput(BLT_CString name, BLT_CString type)
{
    ATX_LOG_FINER("set-input");
    return PostMessage(
        new BLT_DecoderServer_SetInputCommandMessage(name, type));
}
/*----------------------------------------------------------------------
|    AlsaOutput_Prepare
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Prepare(AlsaOutput* self)
{
    int ior;

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
    /* we need to be configured already for 'prepare' to work */
    return BLT_FAILURE;

      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* prepare the device */
        ATX_LOG_FINER("snd_pcm_prepare");

        ior = snd_pcm_prepare(self->device_handle);
        if (ior != 0) {
            ATX_LOG_FINER_2("snd_pcm_prepare() failed (%d : %s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }
        break;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* ignore */
        return BLT_SUCCESS;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_PREPARED);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    SilenceRemover_AcceptPending
+---------------------------------------------------------------------*/
static void
SilenceRemover_AcceptPending(SilenceRemover* self)
{
    BLT_MediaPacket* packet = self->input.pending;
    BLT_Result       result;

    if (packet != NULL) {
        result = ATX_List_AddData(self->output.packets, packet);
        if (ATX_FAILED(result)) {
            BLT_MediaPacket_Release(packet);
        }
        self->input.pending = NULL;
        ATX_LOG_FINER("SilenceRemover: accepting pending packet");
    } else {
        ATX_LOG_FINER("SilenceRemover: no pending packet");
    }
}
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_GetStatus
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_GetStatus(BLT_OutputNode*       _self,
                              BLT_OutputNodeStatus* status)
{
    OsxAudioUnitsOutput* self = ATX_SELF(OsxAudioUnitsOutput, BLT_OutputNode);
    
    /* default values */
    status->flags = 0;
    
    pthread_mutex_lock(&self->lock);
    
    /* check if the queue is full */
    if (ATX_List_GetItemCount(self->packet_queue) >= self->max_packets_in_queue) {
        ATX_LOG_FINER("packet queue is full");
        status->flags |= BLT_OUTPUT_NODE_STATUS_QUEUE_FULL;
    }

    /* compute the media time */
    BLT_TimeStamp_Set(status->media_time, 0, 0);
    if (self->media_time_snapshot.rendered_host_time) {
        UInt64 host_time  = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
        UInt64 media_time = BLT_TimeStamp_ToNanos(self->media_time_snapshot.rendered_packet_ts); 
        ATX_LOG_FINER_3("host time = %lld, last rendered packet = %lld, rendered ts = %lld", 
                        host_time, 
                        self->media_time_snapshot.rendered_host_time,
                        media_time);
        if (host_time > self->media_time_snapshot.rendered_host_time) {
            media_time += host_time-self->media_time_snapshot.rendered_host_time;
        } 
        UInt64 max_media_time;
        max_media_time = BLT_TimeStamp_ToNanos(self->media_time_snapshot.rendered_packet_ts) +
                         BLT_TimeStamp_ToNanos(self->media_time_snapshot.rendered_duration);
        ATX_LOG_FINER_2("computed media time = %lld, max media time = %lld",
                        media_time, max_media_time);
        if (media_time > max_media_time) {
            ATX_LOG_FINER("media time clamped to max");
            media_time = max_media_time;
        }
        status->media_time = BLT_TimeStamp_FromNanos(media_time);
        ATX_LOG_FINER_1("media time = %lld", media_time);
    }
    
    pthread_mutex_unlock(&self->lock);

    return BLT_SUCCESS;
}
Exemple #11
0
/*----------------------------------------------------------------------
|    CrossFaderOutputPort_GetPacket
+---------------------------------------------------------------------*/
BLT_METHOD
CrossFaderOutputPort_GetPacket(BLT_PacketProducerInstance* instance,
                               BLT_MediaPacket**           packet)
{
    CrossFader*   fader = (CrossFader*)instance;
    ATX_ListItem* item;

    item = ATX_List_GetFirstItem(fader->output.packets);
    if (item) {
        *packet = ATX_ListItem_GetData(item);
        ATX_List_RemoveItem(fader->output.packets, item);
        ATX_LOG_FINER("CrossFaderInputPort_GetPacket - got one");
        return BLT_SUCCESS;
    } else {
        *packet = NULL;
        ATX_LOG_FINER("CrossFaderInputPort_GetPacket - no more data");
        return BLT_ERROR_PORT_HAS_NO_DATA;
    }
}
/*----------------------------------------------------------------------
|    SilenceRemover_HoldPacket
+---------------------------------------------------------------------*/
static void
SilenceRemover_HoldPacket(SilenceRemover* self, BLT_MediaPacket* packet)
{
    ATX_LOG_FINER("SilenceRemover: holding packet");

    /* accept the previously pending packet if any */
    SilenceRemover_AcceptPending(self);

    /* hold the packet as a pending input */
    self->input.pending = packet;
    BLT_MediaPacket_AddReference(packet);
}
/*----------------------------------------------------------------------
|       AlsaOutput_Deactivate
+---------------------------------------------------------------------*/
BLT_METHOD
AlsaOutput_Deactivate(BLT_MediaNode* _self)
{
    AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode);

    ATX_LOG_FINER("deactivating output");

    /* close the device */
    AlsaOutput_Close(self);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|       AlsaOutput_Stop
+---------------------------------------------------------------------*/
BLT_METHOD
AlsaOutput_Stop(BLT_MediaNode* _self)
{
    AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode);

    ATX_LOG_FINER("stopping output");

    /* reset the device */
    AlsaOutput_Reset(self);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    AlsaOutput_Reset
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Reset(AlsaOutput* self)
{
    ATX_LOG_FINER("resetting output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        ATX_LOG_FINER("snd_pcm_drop");
        snd_pcm_drop(self->device_handle);
        AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);
        break;
    }

    return BLT_SUCCESS;
}
Exemple #16
0
/*----------------------------------------------------------------------
|    AlsaOutput_Drain
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Drain(AlsaOutput* self)
{
    ATX_LOG_FINER("draining output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* drain samples buffered by the driver (wait until they are played) */
        ATX_LOG_FINER("snd_pcm_drain");
        snd_pcm_drain(self->device_handle);
        break;
    }

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|       AlsaOutput_Activate
+---------------------------------------------------------------------*/
BLT_METHOD
AlsaOutput_Activate(BLT_MediaNode* _self, BLT_Stream* stream)
{
    AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode);
    BLT_COMPILER_UNUSED(stream);
        
    ATX_LOG_FINER("activating output");

    /* open the device */
    AlsaOutput_Open(self);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    SilenceRemover_AcceptPacket
+---------------------------------------------------------------------*/
static void
SilenceRemover_AcceptPacket(SilenceRemover* self, BLT_MediaPacket* packet)
{
    BLT_Result result;
    ATX_LOG_FINER("SilenceRemover: accepting packet");

    /* first, use any pending packet */
    SilenceRemover_AcceptPending(self);

    /* add the packet to the output list */
    result = ATX_List_AddData(self->output.packets, packet);
    if (ATX_SUCCEEDED(result)) {
        BLT_MediaPacket_AddReference(packet);
    }
}
/*----------------------------------------------------------------------
|    DcfParser_Deactivate
+---------------------------------------------------------------------*/
BLT_METHOD
DcfParser_Deactivate(BLT_MediaNode* _self)
{
    DcfParser* self = ATX_SELF_EX(DcfParser, BLT_BaseMediaNode, BLT_MediaNode);

    ATX_LOG_FINER("DcfParser::Deactivate");

    /* release the stream */
    ATX_RELEASE_OBJECT(self->output.stream);

    /* call the base class method */
    BLT_BaseMediaNode_Deactivate(_self);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    AlsaOutput_Unprepare
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Unprepare(AlsaOutput* self)
{
    ATX_LOG_FINER("unpreparing output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        break;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* drain any pending samples */
        ATX_LOG_FINER("snd_pcm_drain");
        snd_pcm_drain(self->device_handle);
        
        /* update the state */
        AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);
        break;
    }

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|       OsxAudioUnitsOutput_Deactivate
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Deactivate(BLT_MediaNode* _self)
{
    OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ComponentResult      result;

    ATX_LOG_FINER("OsxAudioUnitsOutput::Deactivate");

    /* un-initialize the device */
    if (self->audio_unit) {
        result = AudioUnitUninitialize(self->audio_unit);
        if (result != noErr) {
            ATX_LOG_WARNING_1("AudioUnitUninitialize failed (%d)", (int)result);
            return BLT_FAILURE;
        }
    }
    
    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|       AlsaOutput_Resume
+---------------------------------------------------------------------*/
BLT_METHOD
AlsaOutput_Resume(BLT_MediaNode* _self)
{
    AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode);
        
    ATX_LOG_FINER("resuming output");

    /* pause the device */
    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        snd_pcm_pause(self->device_handle, 0);
        break;

      default:
        /* ignore */
        break;
    }

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    WaveFormatter_UpdateWavHeader
+---------------------------------------------------------------------*/
static BLT_Result
WaveFormatter_UpdateWavHeader(WaveFormatter* self)
{
    BLT_Result    result;
    unsigned char buffer[4];

    ATX_LOG_FINER_1("WaveFormatter::UpdateWavHeader - size = %d", self->input.size);

    result = ATX_OutputStream_Seek(self->output.stream, 4);
    if (BLT_FAILED(result)) return result;
    ATX_BytesFromInt32Le(buffer, (ATX_Size)self->input.size + 8+16+12);
    ATX_OutputStream_Write(self->output.stream, buffer, 4, NULL);

    result = ATX_OutputStream_Seek(self->output.stream, 40);
    if (BLT_FAILED(result)) return result;

    ATX_BytesFromInt32Le(buffer, (ATX_Size)self->input.size);        
    ATX_OutputStream_Write(self->output.stream, buffer, 4, NULL);

    ATX_LOG_FINER("WaveFormatter::UpdateWavHeader - updated");

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_QueuePacket
+---------------------------------------------------------------------*/
static BLT_Result
OsxAudioUnitsOutput_QueuePacket(OsxAudioUnitsOutput* self, BLT_MediaPacket* packet)
{
    BLT_Result   result   = BLT_SUCCESS;
    unsigned int watchdog = BLT_OSX_AUDIO_UNITS_OUTPUT_MAX_QUEUE_WAIT_COUNT;
    
    ATX_LOG_FINER("queuing packet");
    
    /* lock the queue */
    pthread_mutex_lock(&self->lock);
    
    /* wait for some space in the queue */
    while (ATX_List_GetItemCount(self->packet_queue) >= self->max_packets_in_queue) {
        pthread_mutex_unlock(&self->lock);
        usleep(BLT_OSX_AUDIO_UNITS_OUTPUT_SLEEP_INTERVAL);
        pthread_mutex_lock(&self->lock);
        
        if (--watchdog == 0) {
            ATX_LOG_WARNING("*** the watchdog bit us ***");
            goto end;
        }
    }
    
    /* add the packet to the queue */
    ATX_List_AddData(self->packet_queue, packet);
    ATX_LOG_FINER_1("packet queued, %d in queue", ATX_List_GetItemCount(self->packet_queue));
    
    /* keep a reference to the packet */
    BLT_MediaPacket_AddReference(packet);
    
end:
    /* unlock the queue */
    pthread_mutex_unlock(&self->lock);
    
    return result;
}
/*----------------------------------------------------------------------
|   OsxAudioUnitsOutput_Activate
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Activate(BLT_MediaNode* _self, BLT_Stream* stream)
{
    OsxAudioUnitsOutput*   self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ComponentResult        result;
    AURenderCallbackStruct callback;
    
    BLT_COMPILER_UNUSED(stream);
        
    ATX_LOG_FINER("start");

    /* select the device */
    if (self->audio_device_id) {
        result = AudioUnitSetProperty(self->audio_unit,
                                      kAudioOutputUnitProperty_CurrentDevice,
                                      kAudioUnitScope_Global,
                                      0,
                                      &self->audio_device_id,
                                      sizeof(self->audio_device_id));
        if (result != noErr) {
            ATX_LOG_WARNING_1("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice) failed (%d)", (int)result);
        }
    }

    /* initialize the output */
    if (self->audio_unit) {
        result = AudioUnitInitialize(self->audio_unit);
        if (result != noErr) {
            ATX_LOG_WARNING_1("AudioUnitInitialize failed (%d)", (int)result);
            return BLT_FAILURE;
        }
    }

    /* set some default audio format */
    {
        AudioStreamBasicDescription audio_desc;
        ATX_SetMemory(&audio_desc, 0, sizeof(audio_desc));
        
        /* setup the audio description */
        audio_desc.mFormatID         = kAudioFormatLinearPCM;
        audio_desc.mFormatFlags      = kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
        audio_desc.mFramesPerPacket  = 1;
        audio_desc.mSampleRate       = 44100;
        audio_desc.mChannelsPerFrame = 2;
        audio_desc.mBitsPerChannel   = 16;
        audio_desc.mBytesPerFrame    = (audio_desc.mBitsPerChannel * audio_desc.mChannelsPerFrame) / 8;
        audio_desc.mBytesPerPacket   = audio_desc.mBytesPerFrame * audio_desc.mFramesPerPacket;
        audio_desc.mReserved         = 0;
        result = AudioUnitSetProperty(self->audio_unit,
                                      kAudioUnitProperty_StreamFormat,
                                      kAudioUnitScope_Input,
                                      0,
                                      &audio_desc,
                                      sizeof(audio_desc));
        if (result != noErr) {
            ATX_LOG_WARNING_1("AudioUnitSetProperty failed (%d)", (int)result);
            return BLT_FAILURE;
        }
    }

    /* check for downmix based on the number of supported channels */
    OsxAudioUnitsOutput_CheckDownmix(self);
    
    /* setup the callback */
    callback.inputProc = OsxAudioUnitsOutput_RenderCallback;
    callback.inputProcRefCon = _self;
    result = AudioUnitSetProperty(self->audio_unit, 
                                  kAudioUnitProperty_SetRenderCallback, 
                                  kAudioUnitScope_Input, 
                                  0,
                                  &callback, 
                                  sizeof(callback));
    if (result != noErr) {
        ATX_LOG_SEVERE_1("AudioUnitSetProperty failed when setting callback (%d)", (int)result);
        return BLT_FAILURE;
    }

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    AlsaOutput_Configure
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Configure(AlsaOutput*             self, 
                     const BLT_PcmMediaType* format)
{
    snd_pcm_hw_params_t* hw_params;
    snd_pcm_sw_params_t* sw_params;
    unsigned int         rate = format->sample_rate;
    unsigned int         buffer_time = BLT_ALSA_DEFAULT_BUFFER_TIME;
    snd_pcm_uframes_t    buffer_size = 0;
    snd_pcm_uframes_t    period_size = BLT_ALSA_DEFAULT_PERIOD_SIZE;
    snd_pcm_format_t     pcm_format_id = SND_PCM_FORMAT_UNKNOWN;
    int                  ior;
    BLT_Result           result;

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
        /* first, we need to open the device */
        result = AlsaOutput_Open(self);
        if (BLT_FAILED(result)) return result;

        /* FALLTHROUGH */

      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* check to see if the format has changed */
        if (format->sample_rate     != self->media_type.sample_rate   ||
            format->channel_count   != self->media_type.channel_count ||
            format->bits_per_sample != self->media_type.bits_per_sample) {
            /* new format */

            /* check the format */
            if (format->sample_rate     == 0 ||
                format->channel_count   == 0 ||
                format->bits_per_sample == 0) {
                return BLT_ERROR_INVALID_MEDIA_FORMAT;
            }
        
            /* unprepare (forget current settings) */
            result = AlsaOutput_Unprepare(self);
            if (BLT_FAILED(result)) return result;
        } else {
            /* same format, do nothing */
            return BLT_SUCCESS;
        }
        
        /* FALLTHROUGH */

      case BLT_ALSA_OUTPUT_STATE_OPEN:
        /* configure the device with the new format */
        ATX_LOG_FINER("configuring ALSA device");

        /* copy the format */
        self->media_type = *format;

        ATX_LOG_FINE_3("new format: sr=%d, ch=%d, bps=%d",
                       format->sample_rate,
                       format->channel_count,
                       format->bits_per_sample);

        /* allocate a new blank configuration */
        snd_pcm_hw_params_alloca_no_assert(&hw_params);
        snd_pcm_hw_params_any(self->device_handle, hw_params);

        /* use interleaved access */
        ior = snd_pcm_hw_params_set_access(self->device_handle, hw_params, 
                                           SND_PCM_ACCESS_RW_INTERLEAVED);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_access failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the sample rate */
        ior = snd_pcm_hw_params_set_rate_near(self->device_handle, 
                                              hw_params, 
                                              &rate, NULL);
        if (ior != 0) {
            ATX_LOG_WARNING_3("snd_pcm_hw_params_set_rate_near(%d) failed (%d:%s)", rate, ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the number of channels */
        ior = snd_pcm_hw_params_set_channels(self->device_handle, 
                                             hw_params,
                                             format->channel_count);
        if (ior != 0) {
            ATX_LOG_WARNING_3("snd_pcm_hw_params_set_channels(%d) failed (%d:%s)", format->channel_count, ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the sample format */
        switch (format->sample_format) {
        	case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_S8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_S16_LE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_S24_3LE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_S32_LE;  break;
        		}
        		break;
        		
        	case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_U8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_U16_LE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_U24_3LE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_U32_LE;  break;
        		}
        		break;

        	case BLT_PCM_SAMPLE_FORMAT_FLOAT_LE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_FLOAT_LE");
        		switch (format->bits_per_sample) {
        			case 32: pcm_format_id = SND_PCM_FORMAT_FLOAT_LE; break;
        		}
        		break;

        	case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_S8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_S16_BE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_S24_3BE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_S32_BE;  break;
        		}
        		break;
        		
        	case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_U8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_U16_BE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_U24_3BE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_U32_BE;  break;
        		}
        		break;

        	case BLT_PCM_SAMPLE_FORMAT_FLOAT_BE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_FLOAT_LE");
        		switch (format->bits_per_sample) {
        			case 32: pcm_format_id = SND_PCM_FORMAT_FLOAT_BE; break;
        		}
        		break;
        }

        if (pcm_format_id == SND_PCM_FORMAT_UNKNOWN) {
            return BLT_ERROR_INVALID_MEDIA_TYPE;
        }
        ior = snd_pcm_hw_params_set_format(self->device_handle, 
                                           hw_params,
                                           pcm_format_id);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_format() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the period size */
        ior = snd_pcm_hw_params_set_period_size_near(self->device_handle, 
                                                     hw_params,
                                                     &period_size,
                                                     NULL);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_period_size_near() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }
        
                                                
        /* set the buffer time (duration) */
        ior = snd_pcm_hw_params_set_buffer_time_near(self->device_handle,
                                                     hw_params, 
                                                     &buffer_time,
                                                     NULL);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_buffer_time_near() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* get the actual buffer size */
        snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);

        /* activate this configuration */
        ior = snd_pcm_hw_params(self->device_handle, hw_params);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* configure the software parameters */
        snd_pcm_sw_params_alloca_no_assert(&sw_params);
        snd_pcm_sw_params_current(self->device_handle, sw_params);

        /* set the start threshold to 1/2 the buffer size */
        snd_pcm_sw_params_set_start_threshold(self->device_handle, 
                                              sw_params, 
                                              buffer_size/2);

        /* set the buffer alignment */
        /* NOTE: this call is now obsolete */
        /* snd_pcm_sw_params_set_xfer_align(self->device_handle, sw_params, 1); */

        /* activate the sofware parameters */
        ior = snd_pcm_sw_params(self->device_handle, sw_params);
        if (ior != 0) {
            ATX_LOG_SEVERE_2("snd_pcm_sw_params() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* print status info */
        {
            snd_pcm_uframes_t val;
            ATX_LOG_FINER_1("sample type = %x", pcm_format_id);
            if (rate != format->sample_rate) {
                ATX_LOG_FINER_1("actual sample = %d", rate);
            }
            ATX_LOG_FINER_1("actual buffer time = %d", (int)buffer_time);
            ATX_LOG_FINER_1("buffer size = %d", (int)buffer_size); 
            snd_pcm_sw_params_get_start_threshold(sw_params, &val);
            ATX_LOG_FINER_1("start threshold = %d", (int)val); 
            snd_pcm_sw_params_get_stop_threshold(sw_params, &val);
            ATX_LOG_FINER_1("stop threshold = %d", (int)val); 
            snd_pcm_hw_params_get_period_size(hw_params, &val, NULL);
            ATX_LOG_FINER_1("period size = %d", (int)val);
        }

        break;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::Run
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::Run()
{
    BLT_Result result;

    ATX_LOG_INFO("running");
    
    // create the decoder
    result = BLT_Decoder_Create(&m_Decoder);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_Create"));
        WaitForTerminateMessage();
        return;
    }
        
    // register as the event handler
    BLT_Decoder_SetEventListener(m_Decoder, 
                                 &ATX_BASE(&m_EventListener, 
                                           BLT_EventListener));

    // listen to core property changes
    {
        ATX_Properties* properties;
        BLT_Decoder_GetProperties(m_Decoder, &properties);
        ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_CorePropertyListener, ATX_PropertyListener), NULL);
    }

    // listen to stream property changes
    {
        ATX_Properties* properties;
        BLT_Decoder_GetStreamProperties(m_Decoder, &properties);
        ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_StreamPropertyListener, ATX_PropertyListener), NULL);
    }

    // register builtins 
    result = BLT_Decoder_RegisterBuiltins(m_Decoder);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_RegisterBuiltins"));
        WaitForTerminateMessage();
        return;
    }

    // set default output, default type
    result = BLT_Decoder_SetOutput(m_Decoder, 
                                   BLT_DECODER_DEFAULT_OUTPUT_NAME, 
                                   NULL);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_SetOutput"));
        //WaitForTerminateMessage();
        //return;
    }
    
    // notify the client of the initial state
    m_Client->PostMessage(
        new BLT_DecoderClient_DecoderStateNotificationMessage(STATE_STOPPED));

    // initial status
    BLT_Decoder_GetStatus(m_Decoder, &m_DecoderStatus);
    m_DecoderStatus.position.range = m_PositionUpdateRange;
    NotifyTimeCode();
    NotifyPosition();

    // initial volume
    float volume=0.0f;
    result = BLT_Decoder_GetVolume(m_Decoder, &volume);
    if (BLT_SUCCEEDED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_VolumeNotificationMessage(volume));
    }

    SetupIsComplete();

    // decoding loop
    do {
        do {
            result = m_MessageQueue->PumpMessage(0); // non-blocking
        } while (BLT_SUCCEEDED(result));
        
        if (result != NPT_ERROR_LIST_EMPTY) {
            break;
        }

        if (m_State == STATE_PLAYING) {
            result = BLT_Decoder_PumpPacketWithOptions(m_Decoder, BLT_DECODER_PUMP_OPTION_NON_BLOCKING);
            if (BLT_FAILED(result)) {
                if (result == BLT_ERROR_WOULD_BLOCK || result == BLT_ERROR_PORT_HAS_NO_DATA) {
                    /* not fatal, just wait and try again later */
                    ATX_LOG_FINER("pump would block, waiting a short time");
                    result = m_MessageQueue->PumpMessage(BLT_PLAYER_LOOP_WAIT_DURATION);
                } else {
                    ATX_LOG_FINE_1("stopped on %d", result);
                    if (result != BLT_ERROR_EOS) {
                        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
                            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_DECODING_ERROR,
                            result, 
                            "error from BLT_Decoder_PumpPacketWithOptions"));
                    }
                    SetState(STATE_EOS);
                    result = BLT_SUCCESS;
                }
            } else {
                UpdateStatus();
            }
        } else {
            ATX_LOG_FINE("waiting for message");
            result = m_MessageQueue->PumpMessage(NPT_TIMEOUT_INFINITE);
            ATX_LOG_FINE("got message");
        }
    } while (BLT_SUCCEEDED(result) || result == NPT_ERROR_TIMEOUT);

    ATX_LOG_FINE("received Terminate Message");

    // unregister as an event listener
    BLT_Decoder_SetEventListener(m_Decoder, NULL);

    // destroy the decoder
    if (m_Decoder != NULL) {
        BLT_Decoder_Destroy(m_Decoder);
    }  
    
    // we're done
    SetState(STATE_TERMINATED);
}
/*----------------------------------------------------------------------
|    SilenceRemoverInput_PutPacket
+---------------------------------------------------------------------*/
BLT_METHOD
SilenceRemoverInput_PutPacket(BLT_PacketConsumer* _self,
                              BLT_MediaPacket*    packet)
{
    SilenceRemover* self = ATX_SELF_M(input, SilenceRemover, BLT_PacketConsumer);
    BLT_Flags       packet_flags;
    BLT_Cardinal    zero_head = 0;
    BLT_Cardinal    zero_tail = 0;
    BLT_Offset      payload_offset;
    BLT_Size        payload_size;
    ATX_Result      result;

    ATX_LOG_FINER("SilenceRemoverInput::PutPacket");

    /* get the packet info */
    packet_flags   = BLT_MediaPacket_GetFlags(packet);
    payload_offset = BLT_MediaPacket_GetPayloadOffset(packet);
    payload_size   = BLT_MediaPacket_GetPayloadSize(packet);

    /* scan the packet for zeros */
    if (payload_size != 0) {
        result = ScanPacket(packet, &zero_head, &zero_tail);    
        if (BLT_FAILED(result)) return result;
        if (zero_head || zero_tail) {
            ATX_LOG_FINER_2("SilenceRemoverInput::PutPacket zero_head=%d, zero_tail=%d",
                            (int)zero_head, (int)zero_tail);
        }
    }

    /* decide how to process the packet */
    if (self->state == SILENCE_REMOVER_STATE_START_OF_STREAM) {
        if (zero_head == payload_size) {
            /* packet is all silence */
            if (packet_flags != 0) {
                /* packet has flags, don't discard it, just empty it */
                ATX_LOG_FINER("SilenceRemover: emptying packet");
                BLT_MediaPacket_SetPayloadSize(packet, 0);
                SilenceRemover_AcceptPacket(self, packet);
            } else {
                ATX_LOG_FINER("SilenceRemover: dropping packet");
            }
        } else {
            /* remove silence at the start of the packet */
            BLT_MediaPacket_SetPayloadOffset(packet, payload_offset+zero_head);
            SilenceRemover_AcceptPacket(self, packet);

            /* we're now in the stream unless this is also the end */
            if (!(packet_flags & BLT_MEDIA_PACKET_FLAG_END_OF_STREAM)) {
                ATX_LOG_FINER("SilenceRemover: new state = IN_STREAM");
                self->state =  SILENCE_REMOVER_STATE_IN_STREAM;
            }
        }
    } else {
        /* in stream */
        if (zero_head == payload_size) {
            /* packet is all silence */
            ATX_LOG_FINER("SilenceRemover: packet is all silence");
            if (packet_flags) {
                /* packet has flags, don't discard it, just empty it */
                SilenceRemover_TrimPending(self);
                BLT_MediaPacket_SetPayloadSize(packet, 0);
                SilenceRemover_AcceptPacket(self, packet);
            } else {
                ATX_LOG_FINER("SilenceRemover: dropping packet");
            }
        } else {
            /* accept the pending packet */
            SilenceRemover_AcceptPending(self);
            if (zero_tail) {
                /* packet has some silence at the end */
                ATX_LOG_FINER("SilenceRemover: packet has silence at end");
                SilenceRemover_HoldPacket(self, packet);
            } else {
                /* packet has no silence at the end */
                ATX_LOG_FINER("SilenceRemover: packet has no silence at end");
                SilenceRemover_AcceptPacket(self, packet);
            }
        }
        if (packet_flags & BLT_MEDIA_PACKET_FLAG_END_OF_STREAM ||
            packet_flags & BLT_MEDIA_PACKET_FLAG_START_OF_STREAM) {
            ATX_LOG_FINER("SilenceRemover: new state = START_OF_STREAM");
            self->state = SILENCE_REMOVER_STATE_START_OF_STREAM;
        }
    }

    return BLT_SUCCESS;
}
Exemple #29
0
/*----------------------------------------------------------------------
|    CrossFaderInputPort_PutPacket
+---------------------------------------------------------------------*/
BLT_METHOD
CrossFaderInputPort_PutPacket(BLT_PacketConsumerInstance* instance,
                              BLT_MediaPacket*            packet)
{
    CrossFader*       fader = (CrossFader*)instance;
    BLT_PcmMediaType* media_type;
    ATX_Result        result;

    ATX_LOG_FINER_1("CrossFaderInputPort::PutPacket - state = %s",
                    fader->state == CROSS_FADER_STATE_IN_START ? "START" :
                    fader->state == CROSS_FADER_STATE_IN_MAIN ? "MAIN" :
                    "???");

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

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

    /* check if the media type has changed */
    if (media_type->sample_rate     != fader->input.media_type.sample_rate     ||
        media_type->channel_count   != fader->input.media_type.channel_count   ||
        media_type->bits_per_sample != fader->input.media_type.bits_per_sample ||
        media_type->sample_format   != fader->input.media_type.sample_format) {
        /* media type has changed */
        ATX_LOG_FINER("CrossFaderInputPort::PutPacket - new media type");
        CrossFader_Flush(fader);
        result = CrossFader_SetupInput(fader, media_type);
        if (BLT_FAILED(result)) return result;
    }

    /* decide what to do with the packet */
    switch (fader->state) {
      case CROSS_FADER_STATE_IN_START:
        {
            unsigned int sample;
            BLT_Size size = BLT_MediaPacket_GetPayloadSize(packet);
            short* samples = (short*)BLT_MediaPacket_GetPayloadBuffer(packet);
            float pos = (float)fader->input.position/(float)(44100*4*10);
            float factor = (float)pow(10.0f, -(30.0f-pos*30.0f)/20.0f);
            ATX_LOG_FINDER_1("CrossFaderInputPort::PutPacket - factor = %f", factor);
            for (sample = 0; sample < size/2; sample++) {
                *samples = (short)(((float)*samples)*factor);
                samples++;
            }
            fader->input.position += size;
            if (fader->input.position >= 44100*4*10) {
                fader->input.position = 0;
                fader->state = CROSS_FADER_STATE_IN_MAIN;
            }
        }
        CrossFader_BufferPacket(fader, packet);
        break;

      case CROSS_FADER_STATE_IN_MAIN:
        CrossFader_BufferPacket(fader, packet);
        break;
    }

    return BLT_SUCCESS;
}