예제 #1
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Seek
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Seek(BLT_MediaNode* _self,
                         BLT_SeekMode*  mode,
                         BLT_SeekPoint* point)
{
    OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ComponentResult      result;
    
    BLT_COMPILER_UNUSED(mode);
    BLT_COMPILER_UNUSED(point);


    /* flush the queue */
    pthread_mutex_lock(&self->lock);
    ATX_List_Clear(self->packet_queue);
    pthread_mutex_unlock(&self->lock);
    
    /* reset the device */
    result = AudioUnitReset(self->audio_unit, kAudioUnitScope_Input, 0);
    if (result != noErr) {
        ATX_LOG_WARNING_1("AudioUnitReset failed (%d)", (int)result);
    }

    return BLT_SUCCESS;
}
예제 #2
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Destroy
+---------------------------------------------------------------------*/
static BLT_Result
OsxAudioUnitsOutput_Destroy(OsxAudioUnitsOutput* self)
{
    /* drain the queue */
    OsxAudioUnitsOutput_Drain(&ATX_BASE(self, BLT_OutputNode));

    /* stop the audio pump */
    OsxAudioUnitsOutput_Stop(&ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode));
    
    /* close the audio unit */
    if (self->audio_unit) {
        ComponentResult result;
        
        result = CloseComponent(self->audio_unit);
        if (result != noErr) {
            ATX_LOG_WARNING_1("CloseComponent failed (%d)", (int)result);
        }
    }
    
    /* destroy the queue */
    ATX_List_Destroy(self->packet_queue);
    
    /* destroy the lock */
    pthread_mutex_destroy(&self->lock);
    
    /* destruct the inherited object */
    BLT_BaseMediaNode_Destruct(&ATX_BASE(self, BLT_BaseMediaNode));

    /* free the object memory */
    ATX_FreeMemory(self);

    return BLT_SUCCESS;
}
예제 #3
0
/*----------------------------------------------------------------------
|   BLT_TcpNetworkStream_Create
+---------------------------------------------------------------------*/
BLT_Result 
BLT_TcpNetworkStream_Create(const char* name, ATX_InputStream** stream)
{
    ATX_Socket* sock;
    ATX_String  hostname = ATX_String_Create(name);
    ATX_UInt16  port = BLT_TCP_NETWORK_STREAM_DEFAULT_PORT;
    int         sep;
    ATX_Result  result = ATX_SUCCESS;

    /* default */
    *stream = NULL;

    /* parse the hostname/port */
    sep = ATX_String_FindCharFrom(&hostname, ':', 6);
    if (sep > 0) {
        /* we have a port number */
        int port_long = 0;
        result = ATX_ParseInteger(name+sep+1, &port_long, ATX_FALSE);
        if (ATX_FAILED(result)) {
            ATX_LOG_WARNING("BLT_TcpNetworkStream_Create - invalid port spec");
            goto end;
        }
        port = (ATX_UInt16)port_long;
        ATX_String_SetLength(&hostname, sep);
    }

    /* create a socket */
    result = ATX_TcpClientSocket_Create(&sock);
    if (ATX_FAILED(result)) goto end;
    
    /* connect */
    ATX_LOG_FINE_2("BLT_TcpNetworkStream_Create - connecting to %s:%d",
                   ATX_CSTR(hostname), port);
    result = ATX_Socket_ConnectToHost(sock, ATX_CSTR(hostname), port, BLT_TCP_NETWORK_STREAM_DEFAULT_TIMEOUT);
    if (ATX_FAILED(result)) {
        ATX_LOG_WARNING_1("BLT_TcpNetworkStream_Create - failed to connect (%d)", result);
        goto end;
    }
    ATX_LOG_FINE("BLT_TcpNetworkStream_Create - connected");

    /* return the input stream */
    result = ATX_Socket_GetInputStream(sock, stream);

    /* release the socket */
    ATX_DESTROY_OBJECT(sock);
    
end:
    ATX_String_Destruct(&hostname);
    return result;
}
예제 #4
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Start
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Start(BLT_MediaNode* _self)
{
    OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ComponentResult      result;
    
    /* start the audio unit */
    result = AudioOutputUnitStart(self->audio_unit);
    if (result != noErr) {
        ATX_LOG_WARNING_1("AudioUnitOutputStart failed (%d)", (int)result);
    }
    
    return BLT_SUCCESS;
}
예제 #5
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Stop
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Stop(BLT_MediaNode* _self)
{
    OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ComponentResult      result;
    

    /* flush the queue */
    pthread_mutex_lock(&self->lock);
    ATX_List_Clear(self->packet_queue);
    pthread_mutex_unlock(&self->lock);

    /* stop the and reset audio unit */
    result = AudioOutputUnitStop(self->audio_unit);
    if (result != noErr) {
        ATX_LOG_WARNING_1("AudioUnitOutputStop failed (%d)", (int)result);
    }
    result = AudioUnitReset(self->audio_unit, kAudioUnitScope_Input, 0);
    if (result != noErr) {
        ATX_LOG_WARNING_1("AudioUnitReset failed (%d)", (int)result);
    }
    
    return BLT_SUCCESS;
}
예제 #6
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Resume
+---------------------------------------------------------------------*/
BLT_METHOD
OsxAudioUnitsOutput_Resume(BLT_MediaNode* _self)
{
    OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ComponentResult      result;

    if (self->paused) {
        ATX_LOG_FINE("resuming output");
        self->paused = BLT_FALSE;
        result = AudioOutputUnitStart(self->audio_unit);
        if (result != noErr) {
            ATX_LOG_WARNING_1("AudioUnitOutputStart failed (%d)", (int)result);
        }
    }
    return BLT_SUCCESS;
}
예제 #7
0
/*----------------------------------------------------------------------
|    PcmAdapterInput_PutPacket
+---------------------------------------------------------------------*/
BLT_METHOD
PcmAdapterInput_PutPacket(BLT_PacketConsumer* _self,
                          BLT_MediaPacket*    packet)
{
    PcmAdapter* self = ATX_SELF_M(input, PcmAdapter, BLT_PacketConsumer);
    BLT_Result  result;

    /* transform the packet data */
    result =  BLT_Pcm_ConvertMediaPacket(ATX_BASE(self, BLT_BaseMediaNode).core,
                                         packet, 
                                         &self->output.pcm_type, 
                                         &self->output.packet);
    if (BLT_FAILED(result)) {
        ATX_LOG_WARNING_1("PcmAdapterInput::PutPacket - failed to convert PCM (%d)", result);
    }

    return result;
}
예제 #8
0
/*----------------------------------------------------------------------
|       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;
}
예제 #9
0
/*----------------------------------------------------------------------
|    AlsaOutput_Write
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Write(AlsaOutput* self, void* buffer, BLT_Size size)
{
    int          watchdog = 5;
    int          io_result;
    unsigned int sample_count;
    unsigned int sample_size;
    BLT_Result   result;

    /* ensure that the device is prepared */
    result = AlsaOutput_Prepare(self);
    if (BLT_FAILED(result)) return result;

    /* compute the number of samples */
    sample_size  = self->media_type.channel_count*self->media_type.bits_per_sample/8;
    sample_count = size / sample_size;
                           
    /* write samples to the device and handle underruns */       
    do {
        while (sample_count) {
            io_result = snd_pcm_writei(self->device_handle, 
                                       buffer, sample_count);
            if (io_result > 0) {
                buffer = (void*)((char*)buffer + io_result*sample_size);
                if ((unsigned int)io_result <= sample_count) {
                    sample_count -= io_result;
                } else {
                    /* strange, snd_pcm_writei returned more than we wrote */
                    sample_count = 0;
                }
            } else {
                break;
            }
        }        
        if (sample_count == 0) return BLT_SUCCESS;

        /* we reach this point if the first write failed */
        if (io_result < 0) {
            snd_pcm_status_t* status;
            snd_pcm_state_t   state;
            snd_pcm_status_alloca_no_assert(&status);

            io_result = snd_pcm_status(self->device_handle, status);
            if (io_result != 0) {
                return BLT_FAILURE;
            }
            state = snd_pcm_status_get_state(status);
            if (state == SND_PCM_STATE_XRUN) {
                ATX_LOG_FINE("**** UNDERRUN *****");
            
                /* re-prepare the channel */
                io_result = snd_pcm_prepare(self->device_handle);
                if (io_result != 0) {
                    return BLT_FAILURE;
                }
            } else {
               ATX_LOG_WARNING_1("**** STATE = %d ****", state);
            }
        } else {
            ATX_LOG_WARNING_1("snd_pcm_writei() returned %d", io_result); 
        }
        
        ATX_LOG_FINE("**** RETRY *****");

    } while(watchdog--);

    ATX_LOG_SEVERE("**** THE WATCHDOG BIT US ****");
    return BLT_FAILURE;
}
예제 #10
0
/*----------------------------------------------------------------------
|   Mp4Parser_Seek
+---------------------------------------------------------------------*/
BLT_METHOD
Mp4Parser_Seek(BLT_MediaNode* _self,
               BLT_SeekMode*  mode,
               BLT_SeekPoint* point)
{
    Mp4Parser* self = ATX_SELF_EX(Mp4Parser, BLT_BaseMediaNode, BLT_MediaNode);

    /* estimate the seek point */
    if (ATX_BASE(self, BLT_BaseMediaNode).context == NULL) return BLT_FAILURE;
    BLT_Stream_EstimateSeekPoint(ATX_BASE(self, BLT_BaseMediaNode).context, *mode, point);
    if (!(point->mask & BLT_SEEK_POINT_MASK_TIME_STAMP)) {
        return BLT_FAILURE;
    }

    /* seek to the estimated offset on all tracks */
    AP4_Ordinal sample_index = 0;
    AP4_UI32    ts_ms = point->time_stamp.seconds*1000+point->time_stamp.nanoseconds/1000000;
    if (self->video_output.track) {
        AP4_Result result = self->video_output.track->GetSampleIndexForTimeStampMs(ts_ms, sample_index);
        if (AP4_FAILED(result)) {
            ATX_LOG_WARNING_1("video GetSampleIndexForTimeStampMs failed (%d)", result);
            return BLT_FAILURE;
        }
        ATX_LOG_FINE_1("seeking to video time %d ms", ts_ms);
        
        // go to the nearest sync sample
        self->video_output.sample = self->video_output.track->GetNearestSyncSampleIndex(sample_index);
        if (self->input.reader) {
            self->input.reader->SetSampleIndex(self->video_output.track->GetId(), self->video_output.sample);
        }
        ATX_LOG_FINE_1("seeking to video sync sample %d", self->video_output.sample);
        
        // compute the timestamp of the video sample we're seeking to, so we can pick an audio
        // sample that is close in time (there are many more audio sync points than video)
        AP4_Sample sample;
        if (AP4_SUCCEEDED(self->video_output.track->GetSample(self->video_output.sample, sample))) {
            AP4_UI32 media_timescale = self->video_output.track->GetMediaTimeScale();
            if (media_timescale) {
                ts_ms = (AP4_UI32)((((AP4_UI64)sample.GetCts())*1000)/media_timescale);
                ATX_LOG_FINE_1("sync sample time is %d ms", ts_ms);
            }
        } else {
            ATX_LOG_FINE_1("unable to get sample info for sample %d", self->video_output.sample);
        }
    }
    if (self->audio_output.track) {
        AP4_Result result = self->audio_output.track->GetSampleIndexForTimeStampMs(ts_ms, sample_index);
        if (AP4_FAILED(result)) {
            ATX_LOG_WARNING_1("audio GetSampleIndexForTimeStampMs failed (%d)", result);
            return BLT_FAILURE;
        }
        self->audio_output.sample = sample_index;
        if (self->input.reader) {
            self->input.reader->SetSampleIndex(self->audio_output.track->GetId(), sample_index);
        }
    }
    
    /* set the mode so that the nodes down the chain know the seek has */
    /* already been done on the stream                                 */
    *mode = BLT_SEEK_MODE_IGNORE;

    return BLT_SUCCESS;
}
예제 #11
0
/*----------------------------------------------------------------------
|   Mp4ParserOutput_GetPacket
+---------------------------------------------------------------------*/
BLT_METHOD
Mp4ParserOutput_GetPacket(BLT_PacketProducer* _self,
                          BLT_MediaPacket**   packet)
{
    Mp4ParserOutput* self = ATX_SELF(Mp4ParserOutput, BLT_PacketProducer);

    *packet = NULL;
     
    // if we don't have an input yet, we can't produce packets
    //if (self->parser->input.mp4_file == NULL) {
    //    return BLT_ERROR_PORT_HAS_NO_DATA;
    //}
    
    if (self->track == NULL) {
        return BLT_ERROR_EOS;
    } else {
        // check for end-of-stream
        if (self->sample >= self->track->GetSampleCount()) {
            return BLT_ERROR_EOS;
        }

        // read one sample
        AP4_Sample sample;
        AP4_DataBuffer* sample_buffer = self->sample_buffer;
        AP4_Result result;
        if (self->parser->input.reader) {
            // linear reader mode
            result = self->parser->input.reader->ReadNextSample(self->track->GetId(), sample, *sample_buffer);
            if (AP4_SUCCEEDED(result)) self->sample++;
        } else {
            // normal mode
            result = self->track->ReadSample(self->sample++, sample, *sample_buffer);
        }
        if (AP4_FAILED(result)) {
            ATX_LOG_WARNING_1("ReadSample failed (%d)", result);
            if (result == AP4_ERROR_EOS || result == ATX_ERROR_OUT_OF_RANGE) {
                ATX_LOG_WARNING("incomplete media");
                return BLT_ERROR_INCOMPLETE_MEDIA;
            } else {
                return BLT_ERROR_PORT_HAS_NO_DATA;
            }
        }

        // update the sample description if it has changed
        if (sample.GetDescriptionIndex() != self->sample_description_index) {
            result = Mp4ParserOutput_SetSampleDescription(self, sample.GetDescriptionIndex());
            if (BLT_FAILED(result)) return result;
        }
        
        // decrypt the sample if needed
        if (self->sample_decrypter) {
            self->sample_decrypter->DecryptSampleData(*sample_buffer, *self->sample_decrypted_buffer);
            sample_buffer = self->sample_decrypted_buffer;
        }

        AP4_Size packet_size = sample_buffer->GetDataSize();
        result = BLT_Core_CreateMediaPacket(ATX_BASE(self->parser, BLT_BaseMediaNode).core,
                                            packet_size,
                                            (const BLT_MediaType*)self->media_type,
                                            packet);
        if (BLT_FAILED(result)) return result;
        BLT_MediaPacket_SetPayloadSize(*packet, packet_size);
        void* buffer = BLT_MediaPacket_GetPayloadBuffer(*packet);
        ATX_CopyMemory(buffer, sample_buffer->GetData(), packet_size);

        // set the timestamp
        AP4_UI32 media_timescale = self->track->GetMediaTimeScale();
        if (media_timescale) {
            AP4_UI64 ts = ((AP4_UI64)sample.GetCts())*1000000;
            ts /= media_timescale;
            BLT_TimeStamp bt_ts = {
                (BLT_Int32)(ts / 1000000),
                (BLT_Int32)((ts % 1000000)*1000)
            };
            BLT_MediaPacket_SetTimeStamp(*packet, bt_ts);
        }

        // set packet flags
        if (self->sample == 1) {
            BLT_MediaPacket_SetFlags(*packet, BLT_MEDIA_PACKET_FLAG_START_OF_STREAM);
        }

        return BLT_SUCCESS;
    }
}
예제 #12
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Create
+---------------------------------------------------------------------*/
static BLT_Result
OsxAudioUnitsOutput_Create(BLT_Module*              module,
                           BLT_Core*                core, 
                           BLT_ModuleParametersType parameters_type,
                           const void*              parameters, 
                           BLT_MediaNode**          object)
{
    OsxAudioUnitsOutput*      self;
    BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters;
    AudioDeviceID             audio_device_id = 0;
    AudioUnit                 audio_unit = NULL;
    Component                 component;
    ComponentDescription      component_desc;
    ComponentResult           result;
    BLT_Result                blt_result;
    
    /* check parameters */
    if (parameters == NULL || 
        parameters_type != BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR) {
        return BLT_ERROR_INVALID_PARAMETERS;
    }

    /* parse the name */
    if (!ATX_StringsEqualN(constructor->name, "osxau:", 6)) {
        return BLT_ERROR_INTERNAL;
    }

    /* map the name into a device ID */
    blt_result = OsxAudioUnitsOutput_MapDeviceName(constructor->name+6, &audio_device_id);
    if (BLT_FAILED(blt_result)) return blt_result;
    
    /* get the default output audio unit */
    ATX_SetMemory(&component_desc, 0, sizeof(component_desc));
    component_desc.componentType         = kAudioUnitType_Output;
    component_desc.componentSubType      = audio_device_id?kAudioUnitSubType_HALOutput:kAudioUnitSubType_DefaultOutput;
    component_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    component_desc.componentFlags        = 0;
    component_desc.componentFlagsMask    = 0;
    component = FindNextComponent(NULL, &component_desc);
    if (component == NULL) {
        ATX_LOG_WARNING("FindNextComponent failed");
        return BLT_FAILURE;
    }
    
    /* open the audio unit (we will initialize it later) */
    result = OpenAComponent(component, &audio_unit);
    if (result != noErr) {
        ATX_LOG_WARNING_1("OpenAComponent failed (%d)", (int)result);
        return BLT_FAILURE;
    }

    /* Since SnowLeopard, kAudioHardwarePropertyRunLoop points at the process's main thread.
       Since not all apps service a run loop on the main thread (like command-line apps), we
       need to set the run loop to NULL to tell the HAL to run its own thread for this.
       This is important in order for the HAL to receive events when, for example, the headphones
       are plugged in or out.
       NOTE: this was the default before SnowLeopard (10.6), so we only do this if we're 10.6 or
       after */
    {
        SInt32 major, minor;

        Gestalt(gestaltSystemVersionMajor, &major);
        Gestalt(gestaltSystemVersionMinor, &minor);
        if (major > 10 || (major == 10 && minor >= 6)) {
            ATX_LOG_INFO("configuring the HAL to use its own thread for the run loop");
            CFRunLoopRef null_loop =  NULL;
            AudioObjectPropertyAddress address = { kAudioHardwarePropertyRunLoop, 
                                                   kAudioObjectPropertyScopeGlobal, 
                                                   kAudioObjectPropertyElementMaster };
            AudioObjectSetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, sizeof(CFRunLoopRef), &null_loop);
        }
    }
    
    /* allocate memory for the object */
    self = ATX_AllocateZeroMemory(sizeof(OsxAudioUnitsOutput));
    if (self == NULL) {
        *object = NULL;
        return BLT_ERROR_OUT_OF_MEMORY;
    }

    /* construct the inherited object */
    BLT_BaseMediaNode_Construct(&ATX_BASE(self, BLT_BaseMediaNode), module, core);

    /* construct the object */
    self->audio_device_id            = audio_device_id;
    self->audio_unit                 = audio_unit;
    self->media_type.sample_rate     = 0;
    self->media_type.channel_count   = 0;
    self->media_type.bits_per_sample = 0;

    /* create a lock */
    pthread_mutex_init(&self->lock, NULL);
    
    /* create the packet queue */
    {
        ATX_ListDataDestructor destructor = { NULL, OsxAudioUnitsOutput_QueueItemDestructor };
        ATX_List_CreateEx(&destructor, &self->packet_queue);
        self->max_packets_in_queue = BLT_OSX_AUDIO_UNITS_OUTPUT_DEFAULT_PACKET_QUEUE_SIZE;
    }
    
    /* setup the expected media type */
    BLT_PcmMediaType_Init(&self->expected_media_type);
    self->expected_media_type.sample_format = BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_NE;

    /* setup interfaces */
    ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, ATX_Referenceable);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_PacketConsumer);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_OutputNode);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_MediaPort);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_VolumeControl);
    *object = &ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode);

    return BLT_SUCCESS;
}
예제 #13
0
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_SetStreamFormat
+---------------------------------------------------------------------*/
static BLT_Result
OsxAudioUnitsOutput_SetStreamFormat(OsxAudioUnitsOutput*    self, 
                                    const BLT_PcmMediaType* media_type)
{
    OSStatus                    result;
    AudioStreamBasicDescription audio_desc;
    
    /* setup the audio description */
    audio_desc.mFormatID         = kAudioFormatLinearPCM;
    audio_desc.mFormatFlags      = kAudioFormatFlagIsPacked;
    audio_desc.mFramesPerPacket  = 1;
    audio_desc.mSampleRate       = media_type->sample_rate;
    audio_desc.mChannelsPerFrame = media_type->channel_count;
    audio_desc.mBitsPerChannel   = media_type->bits_per_sample;
    audio_desc.mBytesPerFrame    = (audio_desc.mBitsPerChannel * audio_desc.mChannelsPerFrame) / 8;
    audio_desc.mBytesPerPacket   = audio_desc.mBytesPerFrame * audio_desc.mFramesPerPacket;
    audio_desc.mReserved         = 0;
    
    /* select the sample format */
    switch (media_type->sample_format) {
        case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE:
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
            break;
        
        case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE:
            break;
            
        case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE:
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
            break;
            
        case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE:
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
            break;
            
        case BLT_PCM_SAMPLE_FORMAT_FLOAT_BE:
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
            break;
            
        case BLT_PCM_SAMPLE_FORMAT_FLOAT_LE:
            audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
            break;
            
        default:
            return BLT_ERROR_INVALID_MEDIA_TYPE;
    }

    /* drain any pending packets before we switch */
    result = OsxAudioUnitsOutput_Drain(&ATX_BASE(self, BLT_OutputNode));
    if (BLT_FAILED(result)) return result;

    /* set the audio unit property */
    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;
    }
    
    /* copy the format */
    self->media_type = *media_type;
    
    return BLT_SUCCESS;
}
예제 #14
0
/*----------------------------------------------------------------------
|   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;
}